aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Core')
-rw-r--r--lib/StaticAnalyzer/Core/CMakeLists.txt1
-rw-r--r--lib/StaticAnalyzer/Core/Calls.cpp353
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp6
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp188
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineObjC.cpp15
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp6
9 files changed, 386 insertions, 191 deletions
diff --git a/lib/StaticAnalyzer/Core/CMakeLists.txt b/lib/StaticAnalyzer/Core/CMakeLists.txt
index 3da91788c6..0061ce1045 100644
--- a/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -8,6 +8,7 @@ add_clang_library(clangStaticAnalyzerCore
BlockCounter.cpp
BugReporter.cpp
BugReporterVisitors.cpp
+ Calls.cpp
Checker.cpp
CheckerContext.cpp
CheckerHelpers.cpp
diff --git a/lib/StaticAnalyzer/Core/Calls.cpp b/lib/StaticAnalyzer/Core/Calls.cpp
new file mode 100644
index 0000000000..ea28cfdf36
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/Calls.cpp
@@ -0,0 +1,353 @@
+//===- Calls.cpp - Wrapper for all function and method calls ------*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file This file defines CallEvent and its subclasses, which represent path-
+/// sensitive instances of different kinds of function and method calls
+/// (C, C++, and Objective-C).
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
+#include "llvm/ADT/SmallSet.h"
+
+using namespace clang;
+using namespace ento;
+
+SVal CallEvent::getArgSVal(unsigned Index) const {
+ const Expr *ArgE = getArgExpr(Index);
+ if (!ArgE)
+ return UnknownVal();
+ return getSVal(ArgE);
+}
+
+SourceRange CallEvent::getArgSourceRange(unsigned Index) const {
+ const Expr *ArgE = getArgExpr(Index);
+ if (!ArgE)
+ return SourceRange();
+ return ArgE->getSourceRange();
+}
+
+QualType CallEvent::getResultType() const {
+ QualType ResultTy = getDeclaredResultType();
+
+ if (const Expr *E = getOriginExpr()) {
+ if (ResultTy.isNull())
+ ResultTy = E->getType();
+
+ // FIXME: This is copied from CallOrObjCMessage, but it seems suspicious.
+ if (E->isGLValue()) {
+ ASTContext &Ctx = State->getStateManager().getContext();
+ ResultTy = Ctx.getPointerType(ResultTy);
+ }
+ }
+
+ return ResultTy;
+}
+
+static bool isCallbackArg(SVal V, QualType T) {
+ // If the parameter is 0, it's harmless.
+ if (V.isZeroConstant())
+ return false;
+
+ // If a parameter is a block or a callback, assume it can modify pointer.
+ if (T->isBlockPointerType() ||
+ T->isFunctionPointerType() ||
+ T->isObjCSelType())
+ return true;
+
+ // Check if a callback is passed inside a struct (for both, struct passed by
+ // reference and by value). Dig just one level into the struct for now.
+
+ if (isa<PointerType>(T) || isa<ReferenceType>(T))
+ T = T->getPointeeType();
+
+ if (const RecordType *RT = T->getAsStructureType()) {
+ const RecordDecl *RD = RT->getDecl();
+ for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ I != E; ++I) {
+ QualType FieldT = I->getType();
+ if (FieldT->isBlockPointerType() || FieldT->isFunctionPointerType())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool CallEvent::hasNonZeroCallbackArg() const {
+ unsigned NumOfArgs = getNumArgs();
+
+ // If calling using a function pointer, assume the function does not
+ // have a callback. TODO: We could check the types of the arguments here.
+ if (!getDecl())
+ return false;
+
+ unsigned Idx = 0;
+ for (CallEvent::param_type_iterator I = param_type_begin(),
+ E = param_type_end();
+ I != E && Idx < NumOfArgs; ++I, ++Idx) {
+ if (NumOfArgs <= Idx)
+ break;
+
+ if (isCallbackArg(getArgSVal(Idx), *I))
+ return true;
+ }
+
+ return false;
+}
+
+/// \brief Returns true if a type is a pointer-to-const or reference-to-const
+/// with no further indirection.
+static bool isPointerToConst(QualType Ty) {
+ QualType PointeeTy = Ty->getPointeeType();
+ if (PointeeTy == QualType())
+ return false;
+ if (!PointeeTy.isConstQualified())
+ return false;
+ if (PointeeTy->isAnyPointerType())
+ return false;
+ return true;
+}
+
+// Try to retrieve the function declaration and find the function parameter
+// types which are pointers/references to a non-pointer const.
+// We do not invalidate the corresponding argument regions.
+static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs,
+ const CallEvent &Call) {
+ const Decl *CallDecl = Call.getDecl();
+ if (!CallDecl)
+ return;
+
+ if (Call.hasNonZeroCallbackArg())
+ return;
+
+ if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(CallDecl)) {
+ const IdentifierInfo *II = FDecl->getIdentifier();
+
+ // List the cases, where the region should be invalidated even if the
+ // argument is const.
+ // FIXME: This is conflating invalidating /contents/ and invalidating
+ // /metadata/. Now that we pass the CallEvent to the checkers, they
+ // should probably be doing this work themselves.
+ if (II) {
+ StringRef FName = II->getName();
+ // - 'int pthread_setspecific(ptheread_key k, const void *)' stores a
+ // value into thread local storage. The value can later be retrieved with
+ // 'void *ptheread_getspecific(pthread_key)'. So even thought the
+ // parameter is 'const void *', the region escapes through the call.
+ // - funopen - sets a buffer for future IO calls.
+ // - ObjC functions that end with "NoCopy" can free memory, of the passed
+ // in buffer.
+ // - Many CF containers allow objects to escape through custom
+ // allocators/deallocators upon container construction.
+ // - NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
+ // be deallocated by NSMapRemove.
+ // - Any call that has a callback as one of the arguments.
+ if (FName == "pthread_setspecific" ||
+ FName == "funopen" ||
+ FName.endswith("NoCopy") ||
+ (FName.startswith("NS") &&
+ (FName.find("Insert") != StringRef::npos)) ||
+ CallOrObjCMessage::isCFCGAllowingEscape(FName))
+ return;
+ }
+ }
+
+ unsigned Idx = 0;
+ for (CallEvent::param_type_iterator I = Call.param_type_begin(),
+ E = Call.param_type_end();
+ I != E; ++I, ++Idx) {
+ if (isPointerToConst(*I))
+ PreserveArgs.insert(Idx);
+ }
+}
+
+ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
+ ProgramStateRef Orig) const {
+ ProgramStateRef Result = (Orig ? Orig : State);
+
+ SmallVector<const MemRegion *, 8> RegionsToInvalidate;
+ addExtraInvalidatedRegions(RegionsToInvalidate);
+
+ // Indexes of arguments whose values will be preserved by the call.
+ llvm::SmallSet<unsigned, 1> PreserveArgs;
+ findPtrToConstParams(PreserveArgs, *this);
+
+ for (unsigned Idx = 0, Count = getNumArgs(); Idx != Count; ++Idx) {
+ if (PreserveArgs.count(Idx))
+ continue;
+
+ SVal V = getArgSVal(Idx);
+
+ // If we are passing a location wrapped as an integer, unwrap it and
+ // invalidate the values referred by the location.
+ if (nonloc::LocAsInteger *Wrapped = dyn_cast<nonloc::LocAsInteger>(&V))
+ V = Wrapped->getLoc();
+ else if (!isa<Loc>(V))
+ continue;
+
+ if (const MemRegion *R = V.getAsRegion()) {
+ // Invalidate the value of the variable passed by reference.
+
+ // Are we dealing with an ElementRegion? If the element type is
+ // a basic integer type (e.g., char, int) and the underlying region
+ // is a variable region then strip off the ElementRegion.
+ // FIXME: We really need to think about this for the general case
+ // as sometimes we are reasoning about arrays and other times
+ // about (char*), etc., is just a form of passing raw bytes.
+ // e.g., void *p = alloca(); foo((char*)p);
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ // Checking for 'integral type' is probably too promiscuous, but
+ // we'll leave it in for now until we have a systematic way of
+ // handling all of these cases. Eventually we need to come up
+ // with an interface to StoreManager so that this logic can be
+ // appropriately delegated to the respective StoreManagers while
+ // still allowing us to do checker-specific logic (e.g.,
+ // invalidating reference counts), probably via callbacks.
+ if (ER->getElementType()->isIntegralOrEnumerationType()) {
+ const MemRegion *superReg = ER->getSuperRegion();
+ if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) ||
+ isa<ObjCIvarRegion>(superReg))
+ R = cast<TypedRegion>(superReg);
+ }
+ // FIXME: What about layers of ElementRegions?
+ }
+
+ // Mark this region for invalidation. We batch invalidate regions
+ // below for efficiency.
+ RegionsToInvalidate.push_back(R);
+ }
+ }
+
+ // Invalidate designated regions using the batch invalidation API.
+ // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate
+ // global variables.
+ return Result->invalidateRegions(RegionsToInvalidate, getOriginExpr(),
+ BlockCount, LCtx, /*Symbols=*/0, this);
+}
+
+CallEvent::param_iterator AnyFunctionCall::param_begin() const {
+ const FunctionDecl *D = getDecl();
+ if (!D)
+ return 0;
+
+ return D->param_begin();
+}
+
+CallEvent::param_iterator AnyFunctionCall::param_end() const {
+ const FunctionDecl *D = getDecl();
+ if (!D)
+ return 0;
+
+ return D->param_end();
+}
+
+QualType AnyFunctionCall::getDeclaredResultType() const {
+ const FunctionDecl *D = getDecl();
+ if (!D)
+ return QualType();
+
+ return D->getResultType();
+}
+
+const FunctionDecl *SimpleCall::getDecl() const {
+ const FunctionDecl *D = CE->getDirectCallee();
+ if (D)
+ return D;
+
+ return getSVal(CE->getCallee()).getAsFunctionDecl();
+}
+
+void CXXMemberCall::addExtraInvalidatedRegions(RegionList &Regions) const {
+ const Expr *Base = getOriginExpr()->getImplicitObjectArgument();
+
+ // FIXME: Will eventually need to cope with member pointers. This is
+ // a limitation in getImplicitObjectArgument().
+ if (!Base)
+ return;
+
+ if (const MemRegion *R = getSVal(Base).getAsRegion())
+ Regions.push_back(R);
+}
+
+const BlockDataRegion *BlockCall::getBlockRegion() const {
+ const Expr *Callee = getOriginExpr()->getCallee();
+ const MemRegion *DataReg = getSVal(Callee).getAsRegion();
+
+ return cast<BlockDataRegion>(DataReg);
+}
+
+CallEvent::param_iterator BlockCall::param_begin() const {
+ return getBlockRegion()->getDecl()->param_begin();
+}
+
+CallEvent::param_iterator BlockCall::param_end() const {
+ return getBlockRegion()->getDecl()->param_end();
+}
+
+void BlockCall::addExtraInvalidatedRegions(RegionList &Regions) const {
+ Regions.push_back(getBlockRegion());
+}
+
+QualType BlockCall::getDeclaredResultType() const {
+ QualType BlockTy = getBlockRegion()->getCodeRegion()->getLocationType();
+ return cast<FunctionType>(BlockTy->getPointeeType())->getResultType();
+}
+
+void CXXConstructorCall::addExtraInvalidatedRegions(RegionList &Regions) const {
+ if (Target)
+ Regions.push_back(Target);
+}
+
+CallEvent::param_iterator ObjCMessageInvocation::param_begin() const {
+ const ObjCMethodDecl *D = getDecl();
+ if (!D)
+ return 0;
+
+ return D->param_begin();
+}
+
+CallEvent::param_iterator ObjCMessageInvocation::param_end() const {
+ const ObjCMethodDecl *D = getDecl();
+ if (!D)
+ return 0;
+
+ return D->param_end();
+}
+
+void
+ObjCMessageInvocation::addExtraInvalidatedRegions(RegionList &Regions) const {
+ if (const MemRegion *R = getReceiverSVal().getAsRegion())
+ Regions.push_back(R);
+}
+
+QualType ObjCMessageInvocation::getDeclaredResultType() const {
+ const ObjCMethodDecl *D = getDecl();
+ if (!D)
+ return QualType();
+
+ return D->getResultType();
+}
+
+SVal ObjCMessageInvocation::getReceiverSVal() const {
+ // FIXME: Is this the best way to handle class receivers?
+ if (!isInstanceMessage())
+ return UnknownVal();
+
+ const Expr *Base = Msg.getInstanceReceiver();
+ if (Base)
+ return getSVal(Base);
+
+ // An instance message with no expression means we are sending to super.
+ // In this case the object reference is the same as 'self'.
+ const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl();
+ assert(SelfDecl && "No message receiver Expr, but not in an ObjC method");
+ return loc::MemRegionVal(State->getRegion(SelfDecl, LCtx));
+}
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 8a6ea1d0f8..b3d93cfe35 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -431,7 +431,7 @@ CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
const StoreManager::InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
- const CallOrObjCMessage *Call) {
+ const CallEvent *Call) {
for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) {
// If any checker declares the state infeasible (or if it starts that way),
// bail out.
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index a206a1a2fb..74c65c8be0 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -185,7 +185,7 @@ ExprEngine::processRegionChanges(ProgramStateRef state,
const StoreManager::InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> Explicits,
ArrayRef<const MemRegion *> Regions,
- const CallOrObjCMessage *Call) {
+ const CallEvent *Call) {
return getCheckerManager().runCheckersForRegionChanges(state, invalidated,
Explicits, Regions, Call);
}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index b462e010d2..b74d46f17c 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -14,7 +14,7 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtCXX.h"
@@ -125,7 +125,9 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
const LocationContext *LC = Pred->getLocationContext();
ProgramStateRef state = Pred->getState();
- state = invalidateArguments(state, CallOrObjCMessage(E, state, LC), LC);
+ CXXConstructorCall Call(E, state, LC);
+ unsigned BlockCount = currentBuilderContext->getCurrentBlockCount();
+ state = Call.invalidateRegions(BlockCount);
Bldr.generateNode(E, Pred, state);
}
}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index d46e65c5e7..0cbf4829ab 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -13,7 +13,7 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
#include "clang/AST/DeclCXX.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/SaveAndRestore.h"
@@ -307,179 +307,6 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst,
return true;
}
-static bool isPointerToConst(const ParmVarDecl *ParamDecl) {
- QualType PointeeTy = ParamDecl->getOriginalType()->getPointeeType();
- if (PointeeTy != QualType() && PointeeTy.isConstQualified() &&
- !PointeeTy->isAnyPointerType() && !PointeeTy->isReferenceType()) {
- return true;
- }
- return false;
-}
-
-// Try to retrieve the function declaration and find the function parameter
-// types which are pointers/references to a non-pointer const.
-// We do not invalidate the corresponding argument regions.
-static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs,
- const CallOrObjCMessage &Call) {
- const Decl *CallDecl = Call.getDecl();
- if (!CallDecl)
- return;
-
- if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(CallDecl)) {
- const IdentifierInfo *II = FDecl->getIdentifier();
-
- // List the cases, where the region should be invalidated even if the
- // argument is const.
- if (II) {
- StringRef FName = II->getName();
- // - 'int pthread_setspecific(ptheread_key k, const void *)' stores a
- // value into thread local storage. The value can later be retrieved with
- // 'void *ptheread_getspecific(pthread_key)'. So even thought the
- // parameter is 'const void *', the region escapes through the call.
- // - funopen - sets a buffer for future IO calls.
- // - ObjC functions that end with "NoCopy" can free memory, of the passed
- // in buffer.
- // - Many CF containers allow objects to escape through custom
- // allocators/deallocators upon container construction.
- // - NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
- // be deallocated by NSMapRemove.
- // - Any call that has a callback as one of the arguments.
- if (FName == "pthread_setspecific" ||
- FName == "funopen" ||
- FName.endswith("NoCopy") ||
- (FName.startswith("NS") &&
- (FName.find("Insert") != StringRef::npos)) ||
- Call.isCFCGAllowingEscape(FName) ||
- Call.hasNonZeroCallbackArg())
- return;
- }
-
- for (unsigned Idx = 0, E = Call.getNumArgs(); Idx != E; ++Idx) {
- if (FDecl && Idx < FDecl->getNumParams()) {
- if (isPointerToConst(FDecl->getParamDecl(Idx)))
- PreserveArgs.insert(Idx);
- }
- }
- return;
- }
-
- if (const ObjCMethodDecl *MDecl = dyn_cast<ObjCMethodDecl>(CallDecl)) {
- assert(MDecl->param_size() <= Call.getNumArgs());
- unsigned Idx = 0;
-
- if (Call.hasNonZeroCallbackArg())
- return;
-
- for (clang::ObjCMethodDecl::param_const_iterator
- I = MDecl->param_begin(), E = MDecl->param_end(); I != E; ++I, ++Idx) {
- if (isPointerToConst(*I))
- PreserveArgs.insert(Idx);
- }
- return;
- }
-}
-
-ProgramStateRef
-ExprEngine::invalidateArguments(ProgramStateRef State,
- const CallOrObjCMessage &Call,
- const LocationContext *LC) {
- SmallVector<const MemRegion *, 8> RegionsToInvalidate;
-
- if (Call.isObjCMessage()) {
- // Invalidate all instance variables of the receiver of an ObjC message.
- // FIXME: We should be able to do better with inter-procedural analysis.
- if (const MemRegion *MR = Call.getInstanceMessageReceiver(LC).getAsRegion())
- RegionsToInvalidate.push_back(MR);
-
- } else if (Call.isCXXCall()) {
- // Invalidate all instance variables for the callee of a C++ method call.
- // FIXME: We should be able to do better with inter-procedural analysis.
- // FIXME: We can probably do better for const versus non-const methods.
- if (const MemRegion *Callee = Call.getCXXCallee().getAsRegion())
- RegionsToInvalidate.push_back(Callee);
-
- } else if (Call.isFunctionCall()) {
- // Block calls invalidate all captured-by-reference values.
- SVal CalleeVal = Call.getFunctionCallee();
- if (const MemRegion *Callee = CalleeVal.getAsRegion()) {
- if (isa<BlockDataRegion>(Callee))
- RegionsToInvalidate.push_back(Callee);
- }
- }
-
- // Indexes of arguments whose values will be preserved by the call.
- llvm::SmallSet<unsigned, 1> PreserveArgs;
- findPtrToConstParams(PreserveArgs, Call);
-
- for (unsigned idx = 0, e = Call.getNumArgs(); idx != e; ++idx) {
- if (PreserveArgs.count(idx))
- continue;
-
- SVal V = Call.getArgSVal(idx);
-
- // If we are passing a location wrapped as an integer, unwrap it and
- // invalidate the values referred by the location.
- if (nonloc::LocAsInteger *Wrapped = dyn_cast<nonloc::LocAsInteger>(&V))
- V = Wrapped->getLoc();
- else if (!isa<Loc>(V))
- continue;
-
- if (const MemRegion *R = V.getAsRegion()) {
- // Invalidate the value of the variable passed by reference.
-
- // Are we dealing with an ElementRegion? If the element type is
- // a basic integer type (e.g., char, int) and the underlying region
- // is a variable region then strip off the ElementRegion.
- // FIXME: We really need to think about this for the general case
- // as sometimes we are reasoning about arrays and other times
- // about (char*), etc., is just a form of passing raw bytes.
- // e.g., void *p = alloca(); foo((char*)p);
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- // Checking for 'integral type' is probably too promiscuous, but
- // we'll leave it in for now until we have a systematic way of
- // handling all of these cases. Eventually we need to come up
- // with an interface to StoreManager so that this logic can be
- // appropriately delegated to the respective StoreManagers while
- // still allowing us to do checker-specific logic (e.g.,
- // invalidating reference counts), probably via callbacks.
- if (ER->getElementType()->isIntegralOrEnumerationType()) {
- const MemRegion *superReg = ER->getSuperRegion();
- if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) ||
- isa<ObjCIvarRegion>(superReg))
- R = cast<TypedRegion>(superReg);
- }
- // FIXME: What about layers of ElementRegions?
- }
-
- // Mark this region for invalidation. We batch invalidate regions
- // below for efficiency.
- RegionsToInvalidate.push_back(R);
- } else {
- // Nuke all other arguments passed by reference.
- // FIXME: is this necessary or correct? This handles the non-Region
- // cases. Is it ever valid to store to these?
- State = State->unbindLoc(cast<Loc>(V));
- }
- }
-
- // Invalidate designated regions using the batch invalidation API.
-
- // FIXME: We can have collisions on the conjured symbol if the
- // expression *I also creates conjured symbols. We probably want
- // to identify conjured symbols by an expression pair: the enclosing
- // expression (the context) and the expression itself. This should
- // disambiguate conjured symbols.
- unsigned Count = currentBuilderContext->getCurrentBlockCount();
- StoreManager::InvalidatedSymbols IS;
-
- // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate
- // global variables.
- return State->invalidateRegions(RegionsToInvalidate,
- Call.getOriginExpr(), Count, LC,
- &IS, &Call);
-
-}
-
static ProgramStateRef getReplayWithoutInliningState(ExplodedNode *&N,
const CallExpr *CE) {
void *ReplayState = N->getState()->get<ReplayWithoutInlining>();
@@ -524,6 +351,7 @@ void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
SVal L = state->getSVal(Callee, Pred->getLocationContext());
// Figure out the result type. We do this dance to handle references.
+ // FIXME: This doesn't handle C++ methods, blocks, etc.
QualType ResultTy;
if (const FunctionDecl *FD = L.getAsFunctionDecl())
ResultTy = FD->getResultType();
@@ -543,8 +371,16 @@ void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
state = state->BindExpr(CE, LCtx, RetVal);
// Invalidate the arguments.
- state = Eng.invalidateArguments(state, CallOrObjCMessage(CE, state, LCtx),
- LCtx);
+ if (const CXXMemberCallExpr *MemberCE = dyn_cast<CXXMemberCallExpr>(CE)) {
+ CXXMemberCall Call(MemberCE, state, LCtx);
+ state = Call.invalidateRegions(Count);
+ } else if (isa<BlockDataRegion>(L.getAsRegion())) {
+ BlockCall Call(CE, state, LCtx);
+ state = Call.invalidateRegions(Count);
+ } else {
+ FunctionCall Call(CE, state, LCtx);
+ state = Call.invalidateRegions(Count);
+ }
// And make the result node.
Bldr.generateNode(CE, Pred, state);
diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index be9a26b1f5..d35d999b5e 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
@@ -246,6 +247,9 @@ void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr,
ExplodedNode *Pred,
ProgramStateRef state,
bool GenSink) {
+ const LocationContext *LCtx = Pred->getLocationContext();
+ unsigned BlockCount = currentBuilderContext->getCurrentBlockCount();
+
// First handle the return value.
SVal ReturnValue = UnknownVal();
@@ -259,7 +263,7 @@ void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr,
// These methods return their receivers.
const Expr *ReceiverE = msg.getInstanceReceiver();
if (ReceiverE)
- ReturnValue = state->getSVal(ReceiverE, Pred->getLocationContext());
+ ReturnValue = state->getSVal(ReceiverE, LCtx);
break;
}
}
@@ -268,18 +272,17 @@ void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr,
if (ReturnValue.isUnknown()) {
SValBuilder &SVB = getSValBuilder();
QualType ResultTy = msg.getResultType(getContext());
- unsigned Count = currentBuilderContext->getCurrentBlockCount();
const Expr *CurrentE = cast<Expr>(currentStmt);
- const LocationContext *LCtx = Pred->getLocationContext();
- ReturnValue = SVB.getConjuredSymbolVal(NULL, CurrentE, LCtx, ResultTy, Count);
+ ReturnValue = SVB.getConjuredSymbolVal(NULL, CurrentE, LCtx, ResultTy,
+ BlockCount);
}
// Bind the return value.
- const LocationContext *LCtx = Pred->getLocationContext();
state = state->BindExpr(currentStmt, LCtx, ReturnValue);
// Invalidate the arguments (and the receiver)
- state = invalidateArguments(state, CallOrObjCMessage(msg, state, LCtx), LCtx);
+ ObjCMessageInvocation Invocation(msg, state, LCtx);
+ state = Invocation.invalidateRegions(BlockCount);
// And create the new node.
Bldr.generateNode(msg.getMessageExpr(), Pred, state, GenSink);
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index a666de0c5c..d7668dec1a 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -157,7 +157,7 @@ ProgramState::invalidateRegions(ArrayRef<const MemRegion *> Regions,
const Expr *E, unsigned Count,
const LocationContext *LCtx,
StoreManager::InvalidatedSymbols *IS,
- const CallOrObjCMessage *Call) const {
+ const CallEvent *Call) const {
if (!IS) {
StoreManager::InvalidatedSymbols invalidated;
return invalidateRegionsImpl(Regions, E, Count, LCtx,
@@ -171,7 +171,7 @@ ProgramState::invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions,
const Expr *E, unsigned Count,
const LocationContext *LCtx,
StoreManager::InvalidatedSymbols &IS,
- const CallOrObjCMessage *Call) const {
+ const CallEvent *Call) const {
ProgramStateManager &Mgr = getStateManager();
SubEngine* Eng = Mgr.getOwningEngine();
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index 1698316d61..a8e47ff8e2 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -20,7 +20,7 @@
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
@@ -252,7 +252,7 @@ public:
const Expr *E, unsigned Count,
const LocationContext *LCtx,
InvalidatedSymbols &IS,
- const CallOrObjCMessage *Call,
+ const CallEvent *Call,
InvalidatedRegions *Invalidated);
public: // Made public for helper classes.
@@ -790,7 +790,7 @@ StoreRef RegionStoreManager::invalidateRegions(Store store,
const Expr *Ex, unsigned Count,
const LocationContext *LCtx,
InvalidatedSymbols &IS,
- const CallOrObjCMessage *Call,
+ const CallEvent *Call,
InvalidatedRegions *Invalidated) {
invalidateRegionsWorker W(*this, StateMgr,
RegionStoreManager::GetRegionBindings(store),