Author: Gabor Horvath Date: 2019-12-10T08:51:33-08:00 New Revision: f3a28202ef58551db15818f8f51afd21e0f3e231
URL: https://github.com/llvm/llvm-project/commit/f3a28202ef58551db15818f8f51afd21e0f3e231 DIFF: https://github.com/llvm/llvm-project/commit/f3a28202ef58551db15818f8f51afd21e0f3e231.diff LOG: [analyzer] Keep track of escaped locals We want to escape all symbols that are stored into escaped regions. The problem is, we did not know which local regions were escaped. Until now. This should fix some false positives like the one in the tests. Differential Revision: https://reviews.llvm.org/D71152 Added: Modified: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h clang/lib/StaticAnalyzer/Core/ExprEngine.cpp clang/lib/StaticAnalyzer/Core/ProgramState.cpp clang/test/Analysis/symbol-escape.cpp Removed: ################################################################################ diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 2d0967616ff2..c85a66db3457 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -627,6 +627,9 @@ class ExprEngine : public SubEngine { 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 index bdd12a3ffe33..b6b4a86acbb2 100644 --- 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 @@ class ScanReachableSymbols { 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 index 7789b431c0a6..5866be2b2e7c 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h @@ -149,14 +149,16 @@ class SubEngine { } 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<const MemRegion *> ExplicitRegions, const CallEvent *Call, + RegionAndSymbolInvalidationTraits &HTraits) = 0; virtual ProgramStateRef - notifyCheckersOfPointerEscape(ProgramStateRef State, - const InvalidatedSymbols *Invalidated, - ArrayRef<const MemRegion *> 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 index efbc20f09250..b6f6481c369d 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -193,6 +193,8 @@ typedef llvm::ImmutableMap<ConstructedObjectKey, SVal> REGISTER_TRAIT_WITH_PROGRAMSTATE(ObjectsUnderConstruction, ObjectsUnderConstructionMap) +REGISTER_SET_WITH_PROGRAMSTATE(EscapedLocals, const MemRegion *) + //===----------------------------------------------------------------------===// // Engine construction and deletion. //===----------------------------------------------------------------------===// @@ -723,6 +725,12 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, SymReaper.markLive(MR); } + EscapedLocalsTy EscapedRegions = CleanedState->get<EscapedLocals>(); + for (const MemRegion *MR : EscapedRegions) { + if (!SymReaper.isLiveRegion(MR)) + CleanedState = CleanedState->remove<EscapedLocals>(MR); + } + getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper); // Create a state in which dead bindings are removed from the environment @@ -1194,6 +1202,11 @@ ProgramStateRef ExprEngine::escapeValue(ProgramStateRef State, SVal V, State, Scanner.getSymbols(), /*CallEvent*/ nullptr, K, nullptr); } +ProgramStateRef ExprEngine::processLocalRegionEscape(ProgramStateRef State, + const MemRegion *R) const { + return State->add<EscapedLocals>(R); +} + void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &DstTop) { PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), @@ -2680,7 +2693,8 @@ void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred, // 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 @@ ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, SVal Loc, // Cases (1) and (2). const MemRegion *MR = Loc.getAsRegion(); - if (!MR || !MR->hasStackStorage()) + if (!MR || !MR->hasStackStorage() || State->contains<EscapedLocals>(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 index 14006f79fd0f..35c10a7624e6 100644 --- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -41,7 +41,8 @@ void ProgramStateRelease(const ProgramState *state) { Mgr.freeStates.push_back(s); } } -}} +} // namespace ento +} // namespace clang ProgramState::ProgramState(ProgramStateManager *mgr, const Environment& env, StoreRef st, GenericDataMap gdm) @@ -209,6 +210,13 @@ ProgramState::invalidateRegionsImpl(ValueList Values, 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 index be5dfbcd9ef5..dcdfe7b9717d 100644 --- a/clang/test/Analysis/symbol-escape.cpp +++ b/clang/test/Analysis/symbol-escape.cpp @@ -31,3 +31,12 @@ C **indirect_escape_in_bitwise_op() { 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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits