Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -18,16 +18,18 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h" #include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/ImmutableSet.h" #include "llvm/Support/Allocator.h" #include namespace llvm { class APSInt; -} +} // namespace llvm namespace clang { class ASTContext; @@ -57,6 +59,16 @@ } }; +/// Tag for GDM. +struct EscapedLocals{ + using data_type = llvm::ImmutableSet; +}; +template <> +struct ProgramStateTrait : + public ProgramStatePartialTrait> { + static void *GDMIndex(); +}; + /// \class ProgramState /// ProgramState - This class encapsulates: /// @@ -345,6 +357,9 @@ /// a value of such type. SVal getSValAsScalarOrLoc(const MemRegion *R) const; + /// TODO + bool isEscapedLocal(const MemRegion *R) const; + using region_iterator = const MemRegion **; /// Visits the symbols reachable from the given SVal using the provided @@ -872,8 +887,8 @@ bool scan(const SymExpr *sym); }; -} // end ento namespace +} // namespace ento -} // end clang namespace +} // namespace clang #endif Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -723,6 +723,12 @@ SymReaper.markLive(MR); } + EscapedLocals::data_type 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 @@ -2680,7 +2686,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 +2698,7 @@ // Cases (1) and (2). const MemRegion *MR = Loc.getAsRegion(); - if (!MR || !MR->hasStackStorage()) + if (!MR || !MR->hasStackStorage() || State->isEscapedLocal(MR)) return escapeValue(State, Val, PSK_EscapeOnBind); // Case (3). Index: clang/lib/StaticAnalyzer/Core/ProgramState.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ProgramState.cpp +++ clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -16,6 +16,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h" #include "llvm/Support/raw_ostream.h" @@ -41,7 +42,13 @@ Mgr.freeStates.push_back(s); } } -}} +} // namespace ento +} // namespace clang + +void *ProgramStateTrait::GDMIndex() { + static int index = 0; + return &index; +} ProgramState::ProgramState(ProgramStateManager *mgr, const Environment& env, StoreRef st, GenericDataMap gdm) @@ -209,6 +216,12 @@ ProgramStateRef newState = makeWithStore(newStore); if (CausedByPointerEscape) { + for (const MemRegion *R : Invalidated) { + if (!R->hasStackStorage()) + continue; + newState = newState->add(R->getBaseRegion()); + } + newState = Eng.notifyCheckersOfPointerEscape(newState, IS, TopLevelInvalidated, Call, @@ -642,3 +655,7 @@ } return true; } + +bool ProgramState::isEscapedLocal(const MemRegion *R) const { + return this->contains(R->getBaseRegion()); +} Index: clang/test/Analysis/symbol-escape.cpp =================================================================== --- clang/test/Analysis/symbol-escape.cpp +++ clang/test/Analysis/symbol-escape.cpp @@ -31,3 +31,13 @@ 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: +