aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-01-17 20:45:01 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-01-17 20:45:01 +0000
commit706b4fc47bbc608932d3b491ae19a3b9cde9497b (patch)
tree4adf86a776049cbf7f69a1929c4babcbbef925eb /clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
parent7cc9cf2bf09f069cb2dd947ead05d0b54301fb71 (diff)
Notes
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/ExprEngine.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp101
1 files changed, 66 insertions, 35 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index e92e95354f5f..f917a4c8637b 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -728,7 +728,8 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
// Create a state in which dead bindings are removed from the environment
// and the store. TODO: The function should just return new env and store,
// not a new state.
- CleanedState = StateMgr.removeDeadBindings(CleanedState, SFC, SymReaper);
+ CleanedState = StateMgr.removeDeadBindingsFromEnvironmentAndStore(
+ CleanedState, SFC, SymReaper);
// Process any special transfer function for dead symbols.
// A tag to track convenience transitions, which can be removed at cleanup.
@@ -1171,13 +1172,16 @@ void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE,
}
}
-ProgramStateRef ExprEngine::escapeValue(ProgramStateRef State, SVal V,
- PointerEscapeKind K) const {
+ProgramStateRef ExprEngine::escapeValues(ProgramStateRef State,
+ ArrayRef<SVal> Vs,
+ PointerEscapeKind K,
+ const CallEvent *Call) const {
class CollectReachableSymbolsCallback final : public SymbolVisitor {
- InvalidatedSymbols Symbols;
+ InvalidatedSymbols &Symbols;
public:
- explicit CollectReachableSymbolsCallback(ProgramStateRef) {}
+ explicit CollectReachableSymbolsCallback(InvalidatedSymbols &Symbols)
+ : Symbols(Symbols) {}
const InvalidatedSymbols &getSymbols() const { return Symbols; }
@@ -1186,11 +1190,13 @@ ProgramStateRef ExprEngine::escapeValue(ProgramStateRef State, SVal V,
return true;
}
};
+ InvalidatedSymbols Symbols;
+ CollectReachableSymbolsCallback CallBack(Symbols);
+ for (SVal V : Vs)
+ State->scanReachableSymbols(V, CallBack);
- const CollectReachableSymbolsCallback &Scanner =
- State->scanReachableSymbols<CollectReachableSymbolsCallback>(V);
return getCheckerManager().runCheckersForPointerEscape(
- State, Scanner.getSymbols(), /*CallEvent*/ nullptr, K, nullptr);
+ State, CallBack.getSymbols(), Call, K, nullptr);
}
void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
@@ -1245,6 +1251,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::OMPParallelForDirectiveClass:
case Stmt::OMPParallelForSimdDirectiveClass:
case Stmt::OMPParallelSectionsDirectiveClass:
+ case Stmt::OMPParallelMasterDirectiveClass:
case Stmt::OMPTaskDirectiveClass:
case Stmt::OMPTaskyieldDirectiveClass:
case Stmt::OMPBarrierDirectiveClass:
@@ -1268,6 +1275,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::OMPMasterTaskLoopDirectiveClass:
case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
+ case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
case Stmt::OMPDistributeDirectiveClass:
case Stmt::OMPDistributeParallelForDirectiveClass:
case Stmt::OMPDistributeParallelForSimdDirectiveClass:
@@ -1313,6 +1321,11 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::WhileStmtClass:
case Expr::MSDependentExistsStmtClass:
llvm_unreachable("Stmt should not be in analyzer evaluation loop");
+ case Stmt::ImplicitValueInitExprClass:
+ // These nodes are shared in the CFG and would case caching out.
+ // Moreover, no additional evaluation required for them, the
+ // analyzer can reconstruct these values from the AST.
+ llvm_unreachable("Should be pruned from CFG");
case Stmt::ObjCSubscriptRefExprClass:
case Stmt::ObjCPropertyRefExprClass:
@@ -1383,7 +1396,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::IntegerLiteralClass:
case Stmt::FixedPointLiteralClass:
case Stmt::CharacterLiteralClass:
- case Stmt::ImplicitValueInitExprClass:
case Stmt::CXXScalarValueInitExprClass:
case Stmt::CXXBoolLiteralExprClass:
case Stmt::ObjCBoolLiteralExprClass:
@@ -1426,7 +1438,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
bool IsTemporary = false;
if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(ArgE)) {
- ArgE = MTE->GetTemporaryExpr();
+ ArgE = MTE->getSubExpr();
IsTemporary = true;
}
@@ -1481,7 +1493,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
for (auto Child : Ex->children()) {
assert(Child);
SVal Val = State->getSVal(Child, LCtx);
- State = escapeValue(State, Val, PSK_EscapeOther);
+ State = escapeValues(State, Val, PSK_EscapeOther);
}
Bldr2.generateNode(S, N, State);
@@ -2682,33 +2694,52 @@ void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred,
// destructor. We won't see the destructor during analysis, but it's there.
// (4) We are binding to a MemRegion with stack storage that the store
// does not understand.
+ProgramStateRef ExprEngine::processPointerEscapedOnBind(
+ ProgramStateRef State, ArrayRef<std::pair<SVal, SVal>> LocAndVals,
+ const LocationContext *LCtx, PointerEscapeKind Kind,
+ const CallEvent *Call) {
+ SmallVector<SVal, 8> Escaped;
+ for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) {
+ // Cases (1) and (2).
+ const MemRegion *MR = LocAndVal.first.getAsRegion();
+ if (!MR || !MR->hasStackStorage()) {
+ Escaped.push_back(LocAndVal.second);
+ continue;
+ }
+
+ // Case (3).
+ if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion()))
+ if (VR->hasStackParametersStorage() && VR->getStackFrame()->inTopFrame())
+ if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl())
+ if (!RD->hasTrivialDestructor()) {
+ Escaped.push_back(LocAndVal.second);
+ continue;
+ }
+
+ // Case (4): in order to test that, generate a new state with the binding
+ // added. If it is the same state, then it escapes (since the store cannot
+ // represent the binding).
+ // Do this only if we know that the store is not supposed to generate the
+ // same state.
+ SVal StoredVal = State->getSVal(MR);
+ if (StoredVal != LocAndVal.second)
+ if (State ==
+ (State->bindLoc(loc::MemRegionVal(MR), LocAndVal.second, LCtx)))
+ Escaped.push_back(LocAndVal.second);
+ }
+
+ if (Escaped.empty())
+ return State;
+
+ return escapeValues(State, Escaped, Kind, Call);
+}
+
ProgramStateRef
ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, SVal Loc,
SVal Val, const LocationContext *LCtx) {
-
- // Cases (1) and (2).
- const MemRegion *MR = Loc.getAsRegion();
- if (!MR || !MR->hasStackStorage())
- return escapeValue(State, Val, PSK_EscapeOnBind);
-
- // Case (3).
- if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion()))
- if (VR->hasStackParametersStorage() && VR->getStackFrame()->inTopFrame())
- if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl())
- if (!RD->hasTrivialDestructor())
- return escapeValue(State, Val, PSK_EscapeOnBind);
-
- // Case (4): in order to test that, generate a new state with the binding
- // added. If it is the same state, then it escapes (since the store cannot
- // represent the binding).
- // Do this only if we know that the store is not supposed to generate the
- // same state.
- SVal StoredVal = State->getSVal(MR);
- if (StoredVal != Val)
- if (State == (State->bindLoc(loc::MemRegionVal(MR), Val, LCtx)))
- return escapeValue(State, Val, PSK_EscapeOnBind);
-
- return State;
+ std::pair<SVal, SVal> LocAndVal(Loc, Val);
+ return processPointerEscapedOnBind(State, LocAndVal, LCtx, PSK_EscapeOnBind,
+ nullptr);
}
ProgramStateRef