diff options
author | Artem Dergachev <artem.dergachev@gmail.com> | 2018-02-15 19:17:44 +0000 |
---|---|---|
committer | Artem Dergachev <artem.dergachev@gmail.com> | 2018-02-15 19:17:44 +0000 |
commit | 661ab34a3157150a3b07c06e968e7b6737627e38 (patch) | |
tree | 44a87f81782fffaf294cd9eb07fc6e2213f81935 /clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | |
parent | 24953dc876e9c1248381fff0c478e1ca12c383ea (diff) | |
download | bcm5719-llvm-661ab34a3157150a3b07c06e968e7b6737627e38.tar.gz bcm5719-llvm-661ab34a3157150a3b07c06e968e7b6737627e38.zip |
[analyzer] Compute the correct this-region for temporary destructors.
Inline them if possible - a separate flag is added to control this.
The whole thing is under the cfg-temporary-dtors flag, off by default so far.
Temporary destructors are called at the end of full-expression. If the
temporary is lifetime-extended, automatic destructors kick in instead,
which are not addressed in this patch, and normally already work well
modulo the overally broken support for lifetime extension.
The patch operates by attaching the this-region to the CXXBindTemporaryExpr in
the program state, and then recalling it during destruction that was triggered
by that CXXBindTemporaryExpr. It has become possible because
CXXBindTemporaryExpr is part of the construction context since r325210.
Differential revision: https://reviews.llvm.org/D43104
llvm-svn: 325282
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 42 |
1 files changed, 30 insertions, 12 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 107debdd4c4..8e157b1df3f 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -102,6 +102,7 @@ SVal ExprEngine::makeZeroElementRegion(ProgramStateRef State, SVal LValue, const MemRegion * ExprEngine::getRegionForConstructedObject(const CXXConstructExpr *CE, ExplodedNode *Pred, + const ConstructionContext *CC, EvalCallOptions &CallOpts) { const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef State = Pred->getState(); @@ -109,7 +110,7 @@ ExprEngine::getRegionForConstructedObject(const CXXConstructExpr *CE, // See if we're constructing an existing region by looking at the // current construction context. - if (auto CC = getCurrentCFGElement().getAs<CFGConstructor>()) { + if (CC) { if (const Stmt *TriggerStmt = CC->getTriggerStmt()) { if (const CXXNewExpr *CNE = dyn_cast<CXXNewExpr>(TriggerStmt)) { if (AMgr.getAnalyzerOptions().mayInlineCXXAllocator()) { @@ -225,10 +226,20 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, // the entire array). EvalCallOptions CallOpts; + auto C = getCurrentCFGElement().getAs<CFGConstructor>(); + const ConstructionContext *CC = C ? C->getConstructionContext() : nullptr; + + const CXXBindTemporaryExpr *BTE = nullptr; switch (CE->getConstructionKind()) { case CXXConstructExpr::CK_Complete: { - Target = getRegionForConstructedObject(CE, Pred, CallOpts); + Target = getRegionForConstructedObject(CE, Pred, CC, CallOpts); + if (CC && AMgr.getAnalyzerOptions().includeTemporaryDtorsInCFG() && + !CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion && + CallOpts.IsTemporaryCtorOrDtor) { + // May as well be a ReturnStmt. + BTE = dyn_cast<CXXBindTemporaryExpr>(CC->getTriggerStmt()); + } break; } case CXXConstructExpr::CK_VirtualBase: @@ -296,17 +307,18 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, ExplodedNodeSet DstPreVisit; getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, CE, *this); + // FIXME: Is it possible and/or useful to do this before PreStmt? ExplodedNodeSet PreInitialized; { StmtNodeBuilder Bldr(DstPreVisit, PreInitialized, *currBldrCtx); - if (CE->requiresZeroInitialization()) { - // Type of the zero doesn't matter. - SVal ZeroVal = svalBuilder.makeZeroVal(getContext().CharTy); - - for (ExplodedNodeSet::iterator I = DstPreVisit.begin(), - E = DstPreVisit.end(); - I != E; ++I) { - ProgramStateRef State = (*I)->getState(); + for (ExplodedNodeSet::iterator I = DstPreVisit.begin(), + E = DstPreVisit.end(); + I != E; ++I) { + ProgramStateRef State = (*I)->getState(); + if (CE->requiresZeroInitialization()) { + // Type of the zero doesn't matter. + SVal ZeroVal = svalBuilder.makeZeroVal(getContext().CharTy); + // FIXME: Once we properly handle constructors in new-expressions, we'll // need to invalidate the region before setting a default value, to make // sure there aren't any lingering bindings around. This probably needs @@ -320,9 +332,15 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, // since it's then possible to be initializing one part of a multi- // dimensional array. State = State->bindDefault(loc::MemRegionVal(Target), ZeroVal, LCtx); - Bldr.generateNode(CE, *I, State, /*tag=*/nullptr, - ProgramPoint::PreStmtKind); } + + if (BTE) { + State = addInitializedTemporary(State, BTE, LCtx, + cast<CXXTempObjectRegion>(Target)); + } + + Bldr.generateNode(CE, *I, State, /*tag=*/nullptr, + ProgramPoint::PreStmtKind); } } |