diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 |
| commit | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (patch) | |
| tree | 4adf86a776049cbf7f69a1929c4babcbbef925eb /clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | |
| parent | 7cc9cf2bf09f069cb2dd947ead05d0b54301fb71 (diff) | |
Notes
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/ExprEngine.cpp')
| -rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 101 |
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 |
