From: Jordan Rose Date: Tue, 10 Jul 2012 22:08:01 +0000 (+0000) Subject: [analyzer] Construct stack variables directly in their VarDecl. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=48b6247804eacc262cc5508e0fbb74ed819fbb6e;p=clang [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 --- 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(*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(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(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(InitVal)){ - InitVal = state->getSVal(cast(InitVal).getRegion()); - assert(isa(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(InitVal)){ + InitVal = state->getSVal(cast(InitVal).getRegion()); + assert(isa(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(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 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(ThisVal)) { const CXXMethodDecl *MD = cast(Call.getDecl()); loc::MemRegionVal ThisRegion = svalBuilder.getCXXThis(MD, LCtx); Store = Bind(Store.getStore(), ThisRegion, ThisVal);