summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2018-12-19 23:14:06 +0000
committerArtem Dergachev <artem.dergachev@gmail.com>2018-12-19 23:14:06 +0000
commit179064983aa73dd32c3004eac82af220147962e3 (patch)
tree2e89ee82f7456700e921584bcfdc61fb801b9191 /clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
parent217b3b20d8d2be1781dcd8a0d058f6d111922d53 (diff)
downloadbcm5719-llvm-179064983aa73dd32c3004eac82af220147962e3.tar.gz
bcm5719-llvm-179064983aa73dd32c3004eac82af220147962e3.zip
[analyzer] Improve modeling for returning an object from the top frame with RVO.
Static Analyzer processes the program function-by-function, sometimes diving into other functions ("inlining" them). When an object is returned from an inlined function, Return Value Optimization is modeled, and the returned object is constructed at its return location directly. When an object is returned from the function from which the analysis has started (the top stack frame of the analysis), the return location is unknown. Model it with a SymbolicRegion based on a conjured symbol that is specifically tagged for that purpose, because this is generally the correct way to symbolicate unknown locations in Static Analyzer. Fixes leak false positives when an object is returned from top frame in C++17: objects that are put into a SymbolicRegion-based memory region automatically "escape" and no longer get reported as leaks. This only applies to C++17 return values with destructors, because it produces a redundant CXXBindTemporaryExpr in the call site, which confuses our liveness analysis. The actual fix for liveness analysis is still pending, but it is no longer causing problems. Additionally, re-enable temporary destructor tests in C++17. Differential Revision: https://reviews.llvm.org/D55804 rdar://problem/46217550 llvm-svn: 349696
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp31
1 files changed, 23 insertions, 8 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 1f64976a9f7..6445b9df5a5 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -113,7 +113,9 @@ SVal ExprEngine::makeZeroElementRegion(ProgramStateRef State, SVal LValue,
std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction(
const Expr *E, ProgramStateRef State, const LocationContext *LCtx,
const ConstructionContext *CC, EvalCallOptions &CallOpts) {
- MemRegionManager &MRMgr = getSValBuilder().getRegionManager();
+ SValBuilder &SVB = getSValBuilder();
+ MemRegionManager &MRMgr = SVB.getRegionManager();
+ ASTContext &ACtx = SVB.getContext();
// See if we're constructing an existing region by looking at the
// current construction context.
@@ -139,7 +141,7 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction(
assert(Init->isAnyMemberInitializer());
const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
Loc ThisPtr =
- getSValBuilder().getCXXThis(CurCtor, LCtx->getStackFrame());
+ SVB.getCXXThis(CurCtor, LCtx->getStackFrame());
SVal ThisVal = State->getSVal(ThisPtr);
const ValueDecl *Field;
@@ -199,12 +201,25 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction(
cast<Expr>(SFC->getCallSite()), State, CallerLCtx,
RTC->getConstructionContext(), CallOpts);
} else {
- // We are on the top frame of the analysis.
- // TODO: What exactly happens when we are? Does the temporary object
- // live long enough in the region store in this case? Would checkers
- // think that this object immediately goes out of scope?
- CallOpts.IsTemporaryCtorOrDtor = true;
- SVal V = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx));
+ // We are on the top frame of the analysis. We do not know where is the
+ // object returned to. Conjure a symbolic region for the return value.
+ // TODO: We probably need a new MemRegion kind to represent the storage
+ // of that SymbolicRegion, so that we cound produce a fancy symbol
+ // instead of an anonymous conjured symbol.
+ // TODO: Do we need to track the region to avoid having it dead
+ // too early? It does die too early, at least in C++17, but because
+ // putting anything into a SymbolicRegion causes an immediate escape,
+ // it doesn't cause any leak false positives.
+ const auto *RCC = cast<ReturnedValueConstructionContext>(CC);
+ // Make sure that this doesn't coincide with any other symbol
+ // conjured for the returned expression.
+ static const int TopLevelSymRegionTag = 0;
+ const Expr *RetE = RCC->getReturnStmt()->getRetValue();
+ assert(RetE && "Void returns should not have a construction context");
+ QualType ReturnTy = RetE->getType();
+ QualType RegionTy = ACtx.getPointerType(ReturnTy);
+ SVal V = SVB.conjureSymbolVal(&TopLevelSymRegionTag, RetE, SFC,
+ RegionTy, currBldrCtx->blockCount());
return std::make_pair(State, V);
}
llvm_unreachable("Unhandled return value construction context!");
OpenPOWER on IntegriCloud