diff options
Diffstat (limited to 'lib/StaticAnalyzer')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/CStringChecker.cpp | 7 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp | 21 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 105 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp | 9 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp | 6 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/CallEvent.cpp | 1 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/CheckerManager.cpp | 25 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 122 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ProgramState.cpp | 20 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/RegionStore.cpp | 4 |
10 files changed, 204 insertions, 116 deletions
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index c958bfd50f..9fbf97641f 100644 --- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -64,7 +64,7 @@ public: ProgramStateRef checkRegionChanges(ProgramStateRef state, - const StoreManager::InvalidatedSymbols *, + const InvalidatedSymbols *, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, const CallEvent *Call) const; @@ -816,7 +816,8 @@ ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C, // Invalidate this region. const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); - return state->invalidateRegions(R, E, C.blockCount(), LCtx); + return state->invalidateRegions(R, E, C.blockCount(), LCtx, + /*ResultsInPointerEscape*/ false); } // If we have a non-region value by chance, just remove the binding. @@ -1873,7 +1874,7 @@ bool CStringChecker::wantsRegionChangeUpdate(ProgramStateRef state) const { ProgramStateRef CStringChecker::checkRegionChanges(ProgramStateRef state, - const StoreManager::InvalidatedSymbols *, + const InvalidatedSymbols *, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, const CallEvent *Call) const { diff --git a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp index aec551fdb6..fa2c4ffb11 100644 --- a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp +++ b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp @@ -51,6 +51,7 @@ class CheckerDocumentation : public Checker< check::PreStmt<ReturnStmt>, eval::Assume, check::LiveSymbols, check::RegionChanges, + check::PointerEscape, check::Event<ImplicitNullDerefEvent>, check::ASTDecl<FunctionDecl> > { public: @@ -246,13 +247,31 @@ public: /// check::RegionChanges ProgramStateRef checkRegionChanges(ProgramStateRef State, - const StoreManager::InvalidatedSymbols *Invalidated, + const InvalidatedSymbols *Invalidated, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, const CallEvent *Call) const { return State; } + /// \brief Called when pointers escape. + /// + /// This notifies the checkers about pointer escape, which occurs whenever + /// the analzyer cannot track the symbol any more. For example, as a + /// result of assigning a pointer into a global or when it's passed to a + /// function call the analyzer cannot model. + /// + /// \param State The state at the point of escape. + /// \param Escaped The list of escaped symbols. + /// \param Call The corresponding CallEvent, if the symbols escape as + /// parameters to the given call. + /// \returns Checkers can modify the state by returning a new state. + ProgramStateRef checkPointerEscape(ProgramStateRef State, + const InvalidatedSymbols &Escaped, + const CallEvent *Call) const { + return State; + } + /// check::Event<ImplicitNullDerefEvent> void checkEvent(ImplicitNullDerefEvent Event) const {} diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 26fd1c26ea..af902a0096 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -103,15 +103,14 @@ struct ReallocPair { typedef std::pair<const Stmt*, const MemRegion*> LeakInfo; class MallocChecker : public Checker<check::DeadSymbols, + check::PointerEscape, check::PreStmt<ReturnStmt>, check::PreStmt<CallExpr>, check::PostStmt<CallExpr>, check::PostStmt<BlockExpr>, check::PostObjCMessage, check::Location, - check::Bind, - eval::Assume, - check::RegionChanges> + eval::Assume> { mutable OwningPtr<BugType> BT_DoubleFree; mutable OwningPtr<BugType> BT_Leak; @@ -143,17 +142,10 @@ public: bool Assumption) const; void checkLocation(SVal l, bool isLoad, const Stmt *S, CheckerContext &C) const; - void checkBind(SVal location, SVal val, const Stmt*S, - CheckerContext &C) const; - ProgramStateRef - checkRegionChanges(ProgramStateRef state, - const StoreManager::InvalidatedSymbols *invalidated, - ArrayRef<const MemRegion *> ExplicitRegions, - ArrayRef<const MemRegion *> Regions, - const CallEvent *Call) const; - bool wantsRegionChangeUpdate(ProgramStateRef state) const { - return true; - } + + ProgramStateRef checkPointerEscape(ProgramStateRef State, + const InvalidatedSymbols &Escaped, + const CallEvent *Call) const; void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const; @@ -1254,51 +1246,6 @@ void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S, checkUseAfterFree(Sym, C, S); } -//===----------------------------------------------------------------------===// -// Check various ways a symbol can be invalidated. -// TODO: This logic (the next 3 functions) is copied/similar to the -// RetainRelease checker. We might want to factor this out. -//===----------------------------------------------------------------------===// - -// Stop tracking symbols when a value escapes as a result of checkBind. -// A value escapes in three possible cases: -// (1) we are binding to something that is not a memory region. -// (2) we are binding to a memregion that does not have stack storage -// (3) we are binding to a memregion with stack storage that the store -// does not understand. -void MallocChecker::checkBind(SVal loc, SVal val, const Stmt *S, - CheckerContext &C) const { - // Are we storing to something that causes the value to "escape"? - bool escapes = true; - ProgramStateRef state = C.getState(); - - if (loc::MemRegionVal *regionLoc = dyn_cast<loc::MemRegionVal>(&loc)) { - escapes = !regionLoc->getRegion()->hasStackStorage(); - - if (!escapes) { - // To test (3), 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(regionLoc->getRegion()); - if (StoredVal != val) - escapes = (state == (state->bindLoc(*regionLoc, val))); - } - } - - // If our store can represent the binding and we aren't storing to something - // that doesn't have local storage then just return and have the simulation - // state continue as is. - if (!escapes) - return; - - // Otherwise, find all symbols referenced by 'val' that we are tracking - // and stop tracking them. - state = state->scanReachableSymbols<StopTrackingCallback>(val).getState(); - C.addTransition(state); -} - // If a symbolic region is assumed to NULL (or another constant), stop tracking // it - assuming that allocation failed on this path. ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state, @@ -1485,39 +1432,19 @@ bool MallocChecker::doesNotFreeMemory(const CallEvent *Call, return true; } -// If the symbol we are tracking is invalidated, but not explicitly (ex: the &p -// escapes, when we are tracking p), do not track the symbol as we cannot reason -// about it anymore. -ProgramStateRef -MallocChecker::checkRegionChanges(ProgramStateRef State, - const StoreManager::InvalidatedSymbols *invalidated, - ArrayRef<const MemRegion *> ExplicitRegions, - ArrayRef<const MemRegion *> Regions, - const CallEvent *Call) const { - if (!invalidated || invalidated->empty()) +ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State, + const InvalidatedSymbols &Escaped, + const CallEvent *Call) const { + // If we know that the call does not free memory, keep tracking the top + // level arguments. + if (Call && doesNotFreeMemory(Call, State)) return State; - llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols; - - // If it's a call which might free or reallocate memory, we assume that all - // regions (explicit and implicit) escaped. - // Otherwise, whitelist explicit pointers; we still can track them. - if (!Call || doesNotFreeMemory(Call, State)) { - for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(), - E = ExplicitRegions.end(); I != E; ++I) { - if (const SymbolicRegion *R = (*I)->StripCasts()->getAs<SymbolicRegion>()) - WhitelistedSymbols.insert(R->getSymbol()); - } - } - - for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(), - E = invalidated->end(); I!=E; ++I) { + for (InvalidatedSymbols::const_iterator I = Escaped.begin(), + E = Escaped.end(); + I != E; ++I) { SymbolRef sym = *I; - if (WhitelistedSymbols.count(sym)) - continue; - // The symbol escaped. Note, we assume that if the symbol is released, - // passing it out will result in a use after free. We also keep tracking - // relinquished symbols. + if (const RefState *RS = State->get<RegionState>(sym)) { if (RS->isAllocated()) State = State->remove<RegionState>(sym); diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index 5ab9499a61..b38894ccfa 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -2512,7 +2512,7 @@ public: ProgramStateRef checkRegionChanges(ProgramStateRef state, - const StoreManager::InvalidatedSymbols *invalidated, + const InvalidatedSymbols *invalidated, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, const CallEvent *Call) const; @@ -3176,7 +3176,8 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { Binding = getRefBinding(state, Sym); // Invalidate the argument region. - state = state->invalidateRegions(ArgRegion, CE, C.blockCount(), LCtx); + state = state->invalidateRegions(ArgRegion, CE, C.blockCount(), LCtx, + /*ResultsInPointerEscape*/ false); // Restore the refcount status of the argument. if (Binding) @@ -3443,7 +3444,7 @@ ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state, ProgramStateRef RetainCountChecker::checkRegionChanges(ProgramStateRef state, - const StoreManager::InvalidatedSymbols *invalidated, + const InvalidatedSymbols *invalidated, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, const CallEvent *Call) const { @@ -3457,7 +3458,7 @@ RetainCountChecker::checkRegionChanges(ProgramStateRef state, WhitelistedSymbols.insert(SR->getSymbol()); } - for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(), + for (InvalidatedSymbols::const_iterator I=invalidated->begin(), E = invalidated->end(); I!=E; ++I) { SymbolRef sym = *I; if (WhitelistedSymbols.count(sym)) diff --git a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp index 7485fbb0b4..5f7a4a2da2 100644 --- a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp @@ -87,7 +87,7 @@ public: /// Deal with symbol escape as a byproduct of a region change. ProgramStateRef checkRegionChanges(ProgramStateRef state, - const StoreManager::InvalidatedSymbols *invalidated, + const InvalidatedSymbols *invalidated, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, const CallEvent *Call) const; @@ -304,7 +304,7 @@ bool SimpleStreamChecker::guaranteedNotToCloseFile(const CallEvent &Call) const{ // we cannot reason about it anymore. ProgramStateRef SimpleStreamChecker::checkRegionChanges(ProgramStateRef State, - const StoreManager::InvalidatedSymbols *invalidated, + const InvalidatedSymbols *invalidated, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, const CallEvent *Call) const { @@ -324,7 +324,7 @@ SimpleStreamChecker::checkRegionChanges(ProgramStateRef State, } } - for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(), + for (InvalidatedSymbols::const_iterator I=invalidated->begin(), E = invalidated->end(); I!=E; ++I) { SymbolRef sym = *I; if (WhitelistedSymbols.count(sym)) diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index 60b4d988d6..3709fd94ed 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -199,6 +199,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount, // global variables. return Result->invalidateRegions(RegionsToInvalidate, getOriginExpr(), BlockCount, getLocationContext(), + /*ResultsInPointerEscape*/ true, /*Symbols=*/0, this); } diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp index a4915c0dc0..9591f0cd2e 100644 --- a/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -469,10 +469,10 @@ bool CheckerManager::wantsRegionChangeUpdate(ProgramStateRef state) { /// \brief Run checkers for region changes. ProgramStateRef CheckerManager::runCheckersForRegionChanges(ProgramStateRef state, - const StoreManager::InvalidatedSymbols *invalidated, + const InvalidatedSymbols *invalidated, ArrayRef<const MemRegion *> ExplicitRegions, - ArrayRef<const MemRegion *> Regions, - const CallEvent *Call) { + ArrayRef<const MemRegion *> Regions, + const CallEvent *Call) { for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) { // If any checker declares the state infeasible (or if it starts that way), // bail out. @@ -484,6 +484,21 @@ CheckerManager::runCheckersForRegionChanges(ProgramStateRef state, return state; } +/// \brief Run checkers to process symbol escape event. +ProgramStateRef +CheckerManager::runCheckersForPointerEscape(ProgramStateRef State, + const InvalidatedSymbols &Escaped, + const CallEvent *Call) { + for (unsigned i = 0, e = PointerEscapeCheckers.size(); i != e; ++i) { + // If any checker declares the state infeasible (or if it starts that way), + // bail out. + if (!State) + return NULL; + State = PointerEscapeCheckers[i](State, Escaped, Call); + } + return State; +} + /// \brief Run checkers for handling assumptions on symbolic values. ProgramStateRef CheckerManager::runCheckersForEvalAssume(ProgramStateRef state, @@ -641,6 +656,10 @@ void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn, RegionChangesCheckers.push_back(info); } +void CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn){ + PointerEscapeCheckers.push_back(checkfn); +} + void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) { EvalAssumeCheckers.push_back(checkfn); } diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index efb4f7229f..6b33940463 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -199,7 +199,7 @@ bool ExprEngine::wantsRegionChangeUpdate(ProgramStateRef state) { ProgramStateRef ExprEngine::processRegionChanges(ProgramStateRef state, - const StoreManager::InvalidatedSymbols *invalidated, + const InvalidatedSymbols *invalidated, ArrayRef<const MemRegion *> Explicits, ArrayRef<const MemRegion *> Regions, const CallEvent *Call) { @@ -1588,6 +1588,111 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, } } +namespace { +class CollectReachableSymbolsCallback : public SymbolVisitor { + InvalidatedSymbols Symbols; +public: + CollectReachableSymbolsCallback(ProgramStateRef State) {} + const InvalidatedSymbols &getSymbols() const { return Symbols; } + + bool VisitSymbol(SymbolRef Sym) { + Symbols.insert(Sym); + return true; + } +}; +} // end anonymous namespace + +/// Call PointerEscape callback when a value escapes as a result of bind. +/// A value escapes in three possible cases: +/// (1) we are binding to something that is not a memory region. +/// (2) we are binding to a memregion that does not have stack storage +/// (3) we are binding to a memregion with stack storage that the store +/// does not understand. +ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, + SVal Loc, SVal Val) { + // Are we storing to something that causes the value to "escape"? + bool escapes = true; + + // TODO: Move to StoreManager. + if (loc::MemRegionVal *regionLoc = dyn_cast<loc::MemRegionVal>(&Loc)) { + escapes = !regionLoc->getRegion()->hasStackStorage(); + + if (!escapes) { + // To test (3), 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(regionLoc->getRegion()); + if (StoredVal != Val) + escapes = (State == (State->bindLoc(*regionLoc, Val))); + } + } + + // If our store can represent the binding and we aren't storing to something + // that doesn't have local storage then just return and have the simulation + // state continue as is. + if (!escapes) + return State; + + // Otherwise, find all symbols referenced by 'val' that we are tracking + // and stop tracking them. + CollectReachableSymbolsCallback Scanner = + State->scanReachableSymbols<CollectReachableSymbolsCallback>(Val); + const InvalidatedSymbols &EscapedSymbols = Scanner.getSymbols(); + State = getCheckerManager().runCheckersForPointerEscape(State, + EscapedSymbols, + /*CallEvent*/ 0); + + return State; +} + +/// Call PointerEscape callback when a value escapes as a result of +/// region invalidation. +ProgramStateRef +ExprEngine::processPointerEscapedOnInvalidateRegions(ProgramStateRef State, + const InvalidatedSymbols *Invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, + const CallEvent *Call) { + + if (!Invalidated || Invalidated->empty()) + return State; + + if (!Call) + return getCheckerManager().runCheckersForPointerEscape(State, + *Invalidated, 0); + + // If the symbols were invalidated by a call, we want to find out which ones + // were invalidated directly due to being arguments to the call. + InvalidatedSymbols SymbolsDirectlyInvalidated; + for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(), + E = ExplicitRegions.end(); I != E; ++I) { + if (const SymbolicRegion *R = (*I)->StripCasts()->getAs<SymbolicRegion>()) + SymbolsDirectlyInvalidated.insert(R->getSymbol()); + } + + InvalidatedSymbols SymbolsIndirectlyInvalidated; + for (InvalidatedSymbols::const_iterator I=Invalidated->begin(), + E = Invalidated->end(); I!=E; ++I) { + SymbolRef sym = *I; + if (SymbolsDirectlyInvalidated.count(sym)) + continue; + SymbolsIndirectlyInvalidated.insert(sym); + } + + if (!SymbolsDirectlyInvalidated.empty()) + State = getCheckerManager().runCheckersForPointerEscape(State, + SymbolsDirectlyInvalidated, Call); + + // Notify about the symbols that get indirectly invalidated by the call. + if (!SymbolsIndirectlyInvalidated.empty()) + State = getCheckerManager().runCheckersForPointerEscape(State, + SymbolsIndirectlyInvalidated, /*CallEvent*/ 0); + + return State; +} + /// evalBind - Handle the semantics of binding a value to a specific location. /// This method is used by evalStore and (soon) VisitDeclStmt, and others. void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, @@ -1605,27 +1710,33 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val, StoreE, *this, *PP); + + StmtNodeBuilder Bldr(CheckedSet, Dst, *currBldrCtx); + // If the location is not a 'Loc', it will already be handled by // the checkers. There is nothing left to do. if (!isa<Loc>(location)) { - Dst = CheckedSet; + const ProgramPoint L = PostStore(StoreE, LC, /*Loc*/0, /*tag*/0); + ProgramStateRef state = Pred->getState(); + state = processPointerEscapedOnBind(state, location, Val); + Bldr.generateNode(L, state, Pred); return; } - ExplodedNodeSet TmpDst; - StmtNodeBuilder Bldr(CheckedSet, TmpDst, *currBldrCtx); for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); I!=E; ++I) { ExplodedNode *PredI = *I; ProgramStateRef state = PredI->getState(); + state = processPointerEscapedOnBind(state, location, Val); + // When binding the value, pass on the hint that this is a initialization. // For initializations, we do not need to inform clients of region // changes. state = state->bindLoc(cast<Loc>(location), Val, /* notifyChanges = */ !atDeclInit); - + const MemRegion *LocReg = 0; if (loc::MemRegionVal *LocRegVal = dyn_cast<loc::MemRegionVal>(&location)) { LocReg = LocRegVal->getRegion(); @@ -1634,7 +1745,6 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, const ProgramPoint L = PostStore(StoreE, LC, LocReg, 0); Bldr.generateNode(L, state, PredI); } - Dst.insert(TmpDst); } /// evalStore - Handle the semantics of a store via an assignment. diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp index 3b96cc899f..15662776d9 100644 --- a/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -144,31 +144,41 @@ ProgramStateRef ProgramState::invalidateRegions(ArrayRef<const MemRegion *> Regions, const Expr *E, unsigned Count, const LocationContext *LCtx, - StoreManager::InvalidatedSymbols *IS, + bool ResultsInPointerEscape, + InvalidatedSymbols *IS, const CallEvent *Call) const { if (!IS) { - StoreManager::InvalidatedSymbols invalidated; + InvalidatedSymbols invalidated; return invalidateRegionsImpl(Regions, E, Count, LCtx, + ResultsInPointerEscape, invalidated, Call); } - return invalidateRegionsImpl(Regions, E, Count, LCtx, *IS, Call); + return invalidateRegionsImpl(Regions, E, Count, LCtx, ResultsInPointerEscape, + *IS, Call); } ProgramStateRef ProgramState::invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions, const Expr *E, unsigned Count, const LocationContext *LCtx, - StoreManager::InvalidatedSymbols &IS, + bool ResultsInPointerEscape, + InvalidatedSymbols &IS, const CallEvent *Call) const { ProgramStateManager &Mgr = getStateManager(); SubEngine* Eng = Mgr.getOwningEngine(); - if (Eng && Eng->wantsRegionChangeUpdate(this)) { + if (Eng) { StoreManager::InvalidatedRegions Invalidated; const StoreRef &newStore = Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, LCtx, IS, Call, &Invalidated); + ProgramStateRef newState = makeWithStore(newStore); + + if (ResultsInPointerEscape) + newState = Eng->processPointerEscapedOnInvalidateRegions(newState, + &IS, Regions, Invalidated, Call); + return Eng->processRegionChanges(newState, &IS, Regions, Invalidated, Call); } diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp index 32eb56ca73..9d66c16e73 100644 --- a/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -811,7 +811,7 @@ class invalidateRegionsWorker : public ClusterAnalysis<invalidateRegionsWorker> const Expr *Ex; unsigned Count; const LocationContext *LCtx; - StoreManager::InvalidatedSymbols &IS; + InvalidatedSymbols &IS; StoreManager::InvalidatedRegions *Regions; public: invalidateRegionsWorker(RegionStoreManager &rm, @@ -819,7 +819,7 @@ public: RegionBindingsRef b, const Expr *ex, unsigned count, const LocationContext *lctx, - StoreManager::InvalidatedSymbols &is, + InvalidatedSymbols &is, StoreManager::InvalidatedRegions *r, bool includeGlobals) : ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, includeGlobals), |