diff options
author | Devin Coughlin <dcoughlin@apple.com> | 2016-12-19 22:23:22 +0000 |
---|---|---|
committer | Devin Coughlin <dcoughlin@apple.com> | 2016-12-19 22:23:22 +0000 |
commit | 5b1ee2fad97ceec55c6b22154b425954649a95b8 (patch) | |
tree | 865843eacb97918d695c4289b6dc9f0307986868 /clang/lib | |
parent | d9430944f4bb423a15785a0cea2bc6a76c50ecdb (diff) | |
download | bcm5719-llvm-5b1ee2fad97ceec55c6b22154b425954649a95b8.tar.gz bcm5719-llvm-5b1ee2fad97ceec55c6b22154b425954649a95b8.zip |
[analyzer] Add sink after construction of temporary with no-return destructor.
The analyzer's CFG currently doesn't have nodes for calls to temporary
destructors. This causes the analyzer to explore infeasible paths in which
a no-return destructor would have stopped exploration and so results in false
positives when no-return destructors are used to implement assertions.
To mitigate these false positives, this patch stops generates a sink after
evaluating a constructor on a temporary object that has a no-return destructor.
This results in a loss of coverage because the time at which the destructor is
called may be after the time of construction (especially for lifetime-extended
temporaries).
This addresses PR15599.
rdar://problem/29131566
llvm-svn: 290140
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 011f776d0b0..7e9b2033ca3 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -346,6 +346,30 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, defaultEvalCall(Bldr, *I, *Call); } + // If the CFG was contructed without elements for temporary destructors + // and the just-called constructor created a temporary object then + // stop exploration if the temporary object has a noreturn constructor. + // This can lose coverage because the destructor, if it were present + // in the CFG, would be called at the end of the full expression or + // later (for life-time extended temporaries) -- but avoids infeasible + // paths when no-return temporary destructors are used for assertions. + const AnalysisDeclContext *ADC = LCtx->getAnalysisDeclContext(); + if (!ADC->getCFGBuildOptions().AddTemporaryDtors) { + const MemRegion *Target = Call->getCXXThisVal().getAsRegion(); + if (Target && isa<CXXTempObjectRegion>(Target) && + Call->getDecl()->getParent()->isAnyDestructorNoReturn()) { + + for (ExplodedNode *N : DstEvaluated) { + Bldr.generateSink(CE, N, N->getState()); + } + + // There is no need to run the PostCall and PostStmtchecker + // callbacks because we just generated sinks on all nodes in th + // frontier. + return; + } + } + ExplodedNodeSet DstPostCall; getCheckerManager().runCheckersForPostCall(DstPostCall, DstEvaluated, *Call, *this); |