[clang] f3a2820 - [analyzer] Keep track of escaped locals

Gabor Horvath via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 10 08:53:08 PST 2019


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


        


More information about the cfe-commits mailing list