aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2012-07-10 22:08:01 +0000
committerJordan Rose <jordan_rose@apple.com>2012-07-10 22:08:01 +0000
commit48b6247804eacc262cc5508e0fbb74ed819fbb6e (patch)
tree16956a95560e5e0ba92ca6453f2f620f38f6cdc3 /lib/StaticAnalyzer/Core
parente54cfc7b9990acffd0a8a4ba381717b4bb9f3011 (diff)
[analyzer] Construct stack variables directly in their VarDecl.
Also contains a number of tweaks to inlining that are necessary for constructors and destructors. (I have this enabled on a private branch, but it is very much unstable.) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160023 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core')
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp37
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp53
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp27
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp2
4 files changed, 80 insertions, 39 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 5e0a338084..d78234890b 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -375,6 +375,7 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init,
const FieldDecl *FD = BMI->getAnyMember();
+ // FIXME: This does not work for initializers that call constructors.
SVal FieldLoc = state->getLValue(FD, thisVal);
SVal InitVal = state->getSVal(BMI->getInit(), Pred->getLocationContext());
state = state->bindLoc(FieldLoc, InitVal);
@@ -458,7 +459,27 @@ void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {}
-void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
+static const VarDecl *findDirectConstruction(const DeclStmt *DS,
+ const Expr *Init) {
+ for (DeclStmt::const_decl_iterator I = DS->decl_begin(), E = DS->decl_end();
+ I != E; ++I) {
+ const VarDecl *Var = dyn_cast<VarDecl>(*I);
+ if (!Var)
+ continue;
+ if (Var->getInit() != Init)
+ continue;
+ // FIXME: We need to decide how copy-elision should work here.
+ if (!Var->isDirectInit())
+ break;
+ if (Var->getType()->isReferenceType())
+ break;
+ return Var;
+ }
+
+ return 0;
+}
+
+void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
ExplodedNodeSet &DstTop) {
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
S->getLocStart(),
@@ -724,10 +745,18 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::CXXTemporaryObjectExprClass:
case Stmt::CXXConstructExprClass: {
const CXXConstructExpr *C = cast<CXXConstructExpr>(S);
- // For block-level CXXConstructExpr, we don't have a destination region.
- // Let VisitCXXConstructExpr() create one.
+ const MemRegion *Target = 0;
+
+ const LocationContext *LCtx = Pred->getLocationContext();
+ const ParentMap &PM = LCtx->getParentMap();
+ if (const DeclStmt *DS = dyn_cast_or_null<DeclStmt>(PM.getParent(C)))
+ if (const VarDecl *Var = findDirectConstruction(DS, C))
+ Target = Pred->getState()->getLValue(Var, LCtx).getAsRegion();
+ // If we don't have a destination region, VisitCXXConstructExpr() will
+ // create one.
+
Bldr.takeNodes(Pred);
- VisitCXXConstructExpr(C, 0, Pred, Dst);
+ VisitCXXConstructExpr(C, Target, Pred, Dst);
Bldr.addNodes(Dst);
break;
}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index c2590d5ef2..183a7f5362 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -454,30 +454,37 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
if (const Expr *InitEx = VD->getInit()) {
SVal InitVal = state->getSVal(InitEx, Pred->getLocationContext());
-
- // We bound the temp obj region to the CXXConstructExpr. Now recover
- // the lazy compound value when the variable is not a reference.
- if (AMgr.getLangOpts().CPlusPlus && VD->getType()->isRecordType() &&
- !VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){
- InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion());
- assert(isa<nonloc::LazyCompoundVal>(InitVal));
- }
-
- // Recover some path-sensitivity if a scalar value evaluated to
- // UnknownVal.
- if (InitVal.isUnknown()) {
- QualType Ty = InitEx->getType();
- if (InitEx->isGLValue()) {
- Ty = getContext().getPointerType(Ty);
- }
-
- InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, LC, Ty,
- currentBuilderContext->getCurrentBlockCount());
+
+ if (InitVal == state->getLValue(VD, LC)) {
+ // We constructed the object directly in the variable.
+ // No need to bind anything.
+ B.generateNode(DS, N, state);
+ } else {
+ // We bound the temp obj region to the CXXConstructExpr. Now recover
+ // the lazy compound value when the variable is not a reference.
+ // FIXME: This is probably not correct for most constructors!
+ if (AMgr.getLangOpts().CPlusPlus && VD->getType()->isRecordType() &&
+ !VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){
+ InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion());
+ assert(isa<nonloc::LazyCompoundVal>(InitVal));
+ }
+
+ // Recover some path-sensitivity if a scalar value evaluated to
+ // UnknownVal.
+ if (InitVal.isUnknown()) {
+ QualType Ty = InitEx->getType();
+ if (InitEx->isGLValue()) {
+ Ty = getContext().getPointerType(Ty);
+ }
+
+ InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, LC, Ty,
+ currentBuilderContext->getCurrentBlockCount());
+ }
+ B.takeNodes(N);
+ ExplodedNodeSet Dst2;
+ evalBind(Dst2, DS, N, state->getLValue(VD, LC), InitVal, true);
+ B.addNodes(Dst2);
}
- B.takeNodes(N);
- ExplodedNodeSet Dst2;
- evalBind(Dst2, DS, N, state->getLValue(VD, LC), InitVal, true);
- B.addNodes(Dst2);
}
else {
B.generateNode(DS, N,state->bindDeclWithNoInit(state->getRegion(VD, LC)));
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 2b47bc064d..0d9a6d79c9 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -137,7 +137,7 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
if (const ReturnStmt *RS = dyn_cast_or_null<ReturnStmt>(LastSt)) {
const LocationContext *LCtx = CEBNode->getLocationContext();
SVal V = state->getSVal(RS, LCtx);
- state = state->BindExpr(CE, callerCtx, V);
+ state = state->BindExpr(CE, calleeCtx->getParent(), V);
}
// Bind the constructed object value to CXXConstructExpr.
@@ -147,18 +147,10 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
SVal ThisV = state->getSVal(This);
// Always bind the region to the CXXConstructExpr.
- state = state->BindExpr(CCE, CEBNode->getLocationContext(), ThisV);
+ state = state->BindExpr(CCE, calleeCtx->getParent(), ThisV);
}
}
- static SimpleProgramPointTag retValBindTag("ExprEngine : Bind Return Value");
- PostStmt Loc(LastSt, calleeCtx, &retValBindTag);
- bool isNew;
- ExplodedNode *BindedRetNode = G.getNode(Loc, state, false, &isNew);
- BindedRetNode->addPredecessor(CEBNode, G);
- if (!isNew)
- return;
-
// Step 3: BindedRetNode -> CleanedNodes
// If we can find a statement and a block in the inlined function, run remove
// dead bindings before returning from the call. This is important to ensure
@@ -166,6 +158,14 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
// they occurred.
ExplodedNodeSet CleanedNodes;
if (LastSt && Blk) {
+ static SimpleProgramPointTag retValBind("ExprEngine : Bind Return Value");
+ PostStmt Loc(LastSt, calleeCtx, &retValBind);
+ bool isNew;
+ ExplodedNode *BindedRetNode = G.getNode(Loc, state, false, &isNew);
+ BindedRetNode->addPredecessor(CEBNode, G);
+ if (!isNew)
+ return;
+
NodeBuilderContext Ctx(getCoreEngine(), Blk, BindedRetNode);
currentBuilderContext = &Ctx;
// Here, we call the Symbol Reaper with 0 statement and caller location
@@ -186,7 +186,8 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
// CleanedNodes -> CEENode
CallExitEnd Loc(calleeCtx, callerCtx);
bool isNew;
- ExplodedNode *CEENode = G.getNode(Loc, (*I)->getState(), false, &isNew);
+ ProgramStateRef CEEState = (*I == CEBNode) ? state : (*I)->getState();
+ ExplodedNode *CEENode = G.getNode(Loc, CEEState, false, &isNew);
CEENode->addPredecessor(*I, G);
if (!isNew)
return;
@@ -201,8 +202,12 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
SaveAndRestore<unsigned> CBISave(currentStmtIdx, calleeCtx->getIndex());
// FIXME: This needs to call PostCall.
+ // FIXME: If/when we inline Objective-C messages, this also needs to call
+ // PostObjCMessage.
if (CE)
getCheckerManager().runCheckersForPostStmt(Dst, CEENode, CE, *this, true);
+ else
+ Dst.Add(CEENode);
// Enqueue the next element in the block.
for (ExplodedNodeSet::iterator PSI = Dst.begin(), PSE = Dst.end();
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index d5c88e8ad8..916db13aac 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/lib/StaticAnalyzer/Core/Store.cpp
@@ -47,7 +47,7 @@ StoreRef StoreManager::enterStackFrame(Store OldStore,
// FIXME: We will eventually want to generalize this to handle other non-
// parameter arguments besides 'this' (such as 'self' for ObjC methods).
SVal ThisVal = Call.getCXXThisVal();
- if (!ThisVal.isUndef()) {
+ if (isa<DefinedSVal>(ThisVal)) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(Call.getDecl());
loc::MemRegionVal ThisRegion = svalBuilder.getCXXThis(MD, LCtx);
Store = Bind(Store.getStore(), ThisRegion, ThisVal);