diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -627,6 +627,9 @@ const CallEvent *Call, RegionAndSymbolInvalidationTraits &ITraits) override; + ProgramStateRef processLocalRegionEscape(ProgramStateRef State, + const MemRegion *R) const override; + /// A simple wrapper when you only need to notify checkers of pointer-escape /// of a single value. ProgramStateRef escapeValue(ProgramStateRef State, SVal V, diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -27,7 +27,7 @@ namespace llvm { class APSInt; -} +} // namespace llvm namespace clang { class ASTContext; @@ -872,8 +872,8 @@ bool scan(const SymExpr *sym); }; -} // end ento namespace +} // namespace ento -} // end clang namespace +} // namespace clang #endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h @@ -149,14 +149,16 @@ } virtual ProgramStateRef - processPointerEscapedOnBind(ProgramStateRef State, SVal Loc, SVal Val, const LocationContext *LCtx) = 0; + processPointerEscapedOnBind(ProgramStateRef State, SVal Loc, SVal Val, + const LocationContext *LCtx) = 0; + + virtual ProgramStateRef notifyCheckersOfPointerEscape( + ProgramStateRef State, const InvalidatedSymbols *Invalidated, + ArrayRef ExplicitRegions, const CallEvent *Call, + RegionAndSymbolInvalidationTraits &HTraits) = 0; virtual ProgramStateRef - notifyCheckersOfPointerEscape(ProgramStateRef State, - const InvalidatedSymbols *Invalidated, - ArrayRef ExplicitRegions, - const CallEvent *Call, - RegionAndSymbolInvalidationTraits &HTraits) = 0; + processLocalRegionEscape(ProgramStateRef State, const MemRegion *R) const = 0; /// printJson - Called by ProgramStateManager to print checker-specific data. virtual void printJson(raw_ostream &Out, ProgramStateRef State, diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -193,6 +193,8 @@ REGISTER_TRAIT_WITH_PROGRAMSTATE(ObjectsUnderConstruction, ObjectsUnderConstructionMap) +REGISTER_SET_WITH_PROGRAMSTATE(EscapedLocals, const MemRegion *) + //===----------------------------------------------------------------------===// // Engine construction and deletion. //===----------------------------------------------------------------------===// @@ -723,6 +725,12 @@ SymReaper.markLive(MR); } + EscapedLocalsTy EscapedRegions = CleanedState->get(); + for (const MemRegion *MR : EscapedRegions) { + if (!SymReaper.isLiveRegion(MR)) + CleanedState = CleanedState->remove(MR); + } + getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper); // Create a state in which dead bindings are removed from the environment @@ -1194,6 +1202,11 @@ State, Scanner.getSymbols(), /*CallEvent*/ nullptr, K, nullptr); } +ProgramStateRef ExprEngine::processLocalRegionEscape(ProgramStateRef State, + const MemRegion *R) const { + return State->add(R); +} + void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &DstTop) { PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), @@ -2680,7 +2693,8 @@ // A value escapes in four 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. +// (2) We are binding to a MemRegion that does not have stack storage +// or the stack storage is escaped. // (3) We are binding to a top-level parameter region with a non-trivial // 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 @@ -2691,7 +2705,7 @@ // Cases (1) and (2). const MemRegion *MR = Loc.getAsRegion(); - if (!MR || !MR->hasStackStorage()) + if (!MR || !MR->hasStackStorage() || State->contains(MR)) return escapeValue(State, Val, PSK_EscapeOnBind); // Case (3). diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp --- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -41,7 +41,8 @@ Mgr.freeStates.push_back(s); } } -}} +} // namespace ento +} // namespace clang ProgramState::ProgramState(ProgramStateManager *mgr, const Environment& env, StoreRef st, GenericDataMap gdm) @@ -209,6 +210,13 @@ ProgramStateRef newState = makeWithStore(newStore); if (CausedByPointerEscape) { + for (const MemRegion *R : Invalidated) { + if (!R->hasStackStorage()) + continue; + + newState = Eng.processLocalRegionEscape(newState, R->getBaseRegion()); + } + newState = Eng.notifyCheckersOfPointerEscape(newState, IS, TopLevelInvalidated, Call, diff --git a/clang/test/Analysis/symbol-escape.cpp b/clang/test/Analysis/symbol-escape.cpp --- a/clang/test/Analysis/symbol-escape.cpp +++ b/clang/test/Analysis/symbol-escape.cpp @@ -31,3 +31,12 @@ return Baz; } +void save_ptr(int **); +void delete_saved(); + +void store_to_escaped_region() { + int *p; + save_ptr(&p); + p = new int; + delete_saved(); +} // no-warning