]> granicus.if.org Git - clang/commitdiff
[analyzer] Add the pointer escaped callback.
authorAnna Zaks <ganna@apple.com>
Thu, 20 Dec 2012 00:38:25 +0000 (00:38 +0000)
committerAnna Zaks <ganna@apple.com>
Thu, 20 Dec 2012 00:38:25 +0000 (00:38 +0000)
Instead of using several callbacks to identify the pointer escape event,
checkers now can register for the checkPointerEscape.

Converted the Malloc checker to use the new callback.
SimpleStreamChecker will be converted next.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@170625 91177308-0d34-0410-b5e6-96231b3b80d8

16 files changed:
include/clang/StaticAnalyzer/Core/Checker.h
include/clang/StaticAnalyzer/Core/CheckerManager.h
include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
lib/StaticAnalyzer/Checkers/CStringChecker.cpp
lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
lib/StaticAnalyzer/Checkers/MallocChecker.cpp
lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
lib/StaticAnalyzer/Core/CallEvent.cpp
lib/StaticAnalyzer/Core/CheckerManager.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
lib/StaticAnalyzer/Core/ProgramState.cpp
lib/StaticAnalyzer/Core/RegionStore.cpp

index 9eb1248f6a71f2c28ca25e8371c409dd8c9c20ea..61c1884544f3ce4c1b604f0818e6e8b9d801855d 100644 (file)
@@ -293,7 +293,7 @@ class RegionChanges {
   static ProgramStateRef 
   _checkRegionChanges(void *checker,
                       ProgramStateRef state,
-                      const StoreManager::InvalidatedSymbols *invalidated,
+                      const InvalidatedSymbols *invalidated,
                       ArrayRef<const MemRegion *> Explicits,
                       ArrayRef<const MemRegion *> Regions,
                       const CallEvent *Call) {
@@ -317,6 +317,27 @@ public:
   }
 };
 
+class PointerEscape {
+  template <typename CHECKER>
+  static ProgramStateRef
+  _checkPointerEscape(void *checker,
+                     ProgramStateRef State,
+                     const InvalidatedSymbols &Escaped,
+                     const CallEvent *Call) {
+    return ((const CHECKER *)checker)->checkPointerEscape(State, 
+                                                          Escaped, 
+                                                          Call);
+  }
+
+public:
+  template <typename CHECKER>
+  static void _register(CHECKER *checker, CheckerManager &mgr) {
+    mgr._registerForPointerEscape(
+          CheckerManager::CheckPointerEscapeFunc(checker,
+                                                _checkPointerEscape<CHECKER>));
+  }
+};
+
 template <typename EVENT>
 class Event {
   template <typename CHECKER>
index 710e9c1bca6c86cffef6a48a276f922fa92f0b0a..80e06c1e8421aeb633500b74630f238547bdf544 100644 (file)
@@ -310,11 +310,27 @@ public:
   ///   by a call.
   ProgramStateRef
   runCheckersForRegionChanges(ProgramStateRef state,
-                            const StoreManager::InvalidatedSymbols *invalidated,
+                              const InvalidatedSymbols *invalidated,
                               ArrayRef<const MemRegion *> ExplicitRegions,
                               ArrayRef<const MemRegion *> Regions,
                               const CallEvent *Call);
 
+  /// \brief Run checkers 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 one.
+  ProgramStateRef runCheckersForPointerEscape(ProgramStateRef State,
+                                             const InvalidatedSymbols &Escaped,
+                                             const CallEvent *Call);
+
   /// \brief Run checkers for handling assumptions on symbolic values.
   ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state,
                                                SVal Cond, bool Assumption);
@@ -393,13 +409,18 @@ public:
   typedef CheckerFn<void (ProgramStateRef,SymbolReaper &)> CheckLiveSymbolsFunc;
   
   typedef CheckerFn<ProgramStateRef (ProgramStateRef,
-                                const StoreManager::InvalidatedSymbols *symbols,
+                                const InvalidatedSymbols *symbols,
                                 ArrayRef<const MemRegion *> ExplicitRegions,
                                 ArrayRef<const MemRegion *> Regions,
                                 const CallEvent *Call)>
       CheckRegionChangesFunc;
   
   typedef CheckerFn<bool (ProgramStateRef)> WantsRegionChangeUpdateFunc;
+
+  typedef CheckerFn<ProgramStateRef (ProgramStateRef,
+                                     const InvalidatedSymbols &Escaped,
+                                     const CallEvent *Call)>
+      CheckPointerEscapeFunc;
   
   typedef CheckerFn<ProgramStateRef (ProgramStateRef,
                                           const SVal &cond, bool assumption)>
@@ -441,6 +462,8 @@ public:
   void _registerForRegionChanges(CheckRegionChangesFunc checkfn,
                                  WantsRegionChangeUpdateFunc wantUpdateFn);
 
+  void _registerForPointerEscape(CheckPointerEscapeFunc checkfn);
+
   void _registerForEvalAssume(EvalAssumeFunc checkfn);
 
   void _registerForEvalCall(EvalCallFunc checkfn);
@@ -566,6 +589,8 @@ private:
   };
   std::vector<RegionChangesCheckerInfo> RegionChangesCheckers;
 
+  std::vector<CheckPointerEscapeFunc> PointerEscapeCheckers;
+
   std::vector<EvalAssumeFunc> EvalAssumeCheckers;
 
   std::vector<EvalCallFunc> EvalCallCheckers;
index 151b0d6420aad8324cab0491f2f1c1fead052aa2..7c56062152bcc7982a3712170920847120152c3c 100644 (file)
@@ -262,7 +262,7 @@ public:
   ///  to the store. Used to update checkers that track region values.
   ProgramStateRef 
   processRegionChanges(ProgramStateRef state,
-                       const StoreManager::InvalidatedSymbols *invalidated,
+                       const InvalidatedSymbols *invalidated,
                        ArrayRef<const MemRegion *> ExplicitRegions,
                        ArrayRef<const MemRegion *> Regions,
                        const CallEvent *Call);
@@ -459,6 +459,16 @@ protected:
                 SVal location, SVal Val, bool atDeclInit = false,
                 const ProgramPoint *PP = 0);
 
+  ProgramStateRef processPointerEscapedOnBind(ProgramStateRef State,
+                                              SVal Loc, SVal Val);
+
+  ProgramStateRef processPointerEscapedOnInvalidateRegions(
+                            ProgramStateRef State,
+                            const InvalidatedSymbols *Invalidated,
+                            ArrayRef<const MemRegion *> ExplicitRegions,
+                            ArrayRef<const MemRegion *> Regions,
+                            const CallEvent *Call);
+
 public:
   // FIXME: 'tag' should be removed, and a LocationContext should be used
   // instead.
index cb8dd08a24c19ed20771cd5d9e812f57339169ce..0857d127b7476901b2c2df49922c6b5e09b640b7 100644 (file)
@@ -213,13 +213,25 @@ public:
 
   ProgramStateRef killBinding(Loc LV) const;
 
-  /// invalidateRegions - Returns the state with bindings for the given regions
-  ///  cleared from the store. The regions are provided as a continuous array
-  ///  from Begin to End. Optionally invalidates global regions as well.
+  /// \brief Returns the state with bindings for the given regions
+  ///  cleared from the store.
+  ///
+  /// Optionally invalidates global regions as well.
+  ///
+  /// \param Regions the set of regions to be invalidated.
+  /// \param E the expression that caused the invalidation.
+  /// \param BlockCount the current basic block count.
+  /// \param ResultsInPointerEscape the flag is set to true when
+  /// the invalidation is due to escape of a symbol (representing a pointer).
+  /// For example, due to it being passed as an argument in a call.
+  /// \param IS the set of invalidated symbols.
+  /// \param If Call is non-null, the invalidated regions were directly
+  /// invalidated by the call - as parameters.
   ProgramStateRef invalidateRegions(ArrayRef<const MemRegion *> Regions,
                                const Expr *E, unsigned BlockCount,
                                const LocationContext *LCtx,
-                               StoreManager::InvalidatedSymbols *IS = 0,
+                               bool ResultsInPointerEscape,
+                               InvalidatedSymbols *IS = 0,
                                const CallEvent *Call = 0) const;
 
   /// enterStackFrame - Returns the state for entry to the given stack frame,
@@ -395,7 +407,8 @@ private:
   invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions,
                         const Expr *E, unsigned BlockCount,
                         const LocationContext *LCtx,
-                        StoreManager::InvalidatedSymbols &IS,
+                        bool ResultsInSymbolEscape,
+                        InvalidatedSymbols &IS,
                         const CallEvent *Call) const;
 };
 
index e7f29f4f7c0c75af0290a54395306dea11f69f44..c515105b00d60aa4bd376f9b56c37b48a89d9743 100644 (file)
@@ -35,6 +35,8 @@ class ProgramState;
 class ProgramStateManager;
 class ScanReachableSymbols;
 
+typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols;
+
 class StoreManager {
 protected:
   SValBuilder &svalBuilder;
@@ -168,7 +170,6 @@ public:
   /// associated with the object is recycled.
   virtual void decrementReferenceCount(Store store) {}
 
-  typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols;
   typedef SmallVector<const MemRegion *, 8> InvalidatedRegions;
 
   /// invalidateRegions - Clears out the specified regions from the store,
index 1e710778d9bef974106702aad5aff91192100e98..0e9f25375d31a6b9aa8a26b3aa849166a52b89b0 100644 (file)
@@ -104,7 +104,7 @@ public:
   /// made to the store. Used to update checkers that track region values.
   virtual ProgramStateRef 
   processRegionChanges(ProgramStateRef state,
-                       const StoreManager::InvalidatedSymbols *invalidated,
+                       const InvalidatedSymbols *invalidated,
                        ArrayRef<const MemRegion *> ExplicitRegions,
                        ArrayRef<const MemRegion *> Regions,
                        const CallEvent *Call) = 0;
@@ -116,6 +116,16 @@ public:
     return processRegionChanges(state, 0, MR, MR, 0);
   }
 
+  virtual ProgramStateRef
+  processPointerEscapedOnBind(ProgramStateRef State, SVal Loc, SVal Val) = 0;
+
+  virtual ProgramStateRef
+  processPointerEscapedOnInvalidateRegions(ProgramStateRef State,
+                           const InvalidatedSymbols *Invalidated,
+                           ArrayRef<const MemRegion *> ExplicitRegions,
+                           ArrayRef<const MemRegion *> Regions,
+                           const CallEvent *Call) = 0;
+
   /// printState - Called by ProgramStateManager to print checker-specific data.
   virtual void printState(raw_ostream &Out, ProgramStateRef State,
                           const char *NL, const char *Sep) = 0;
index c958bfd50f22298c432cb0b38961491a428f78ef..9fbf97641f396aad8c11de9f0961624d51ead83f 100644 (file)
@@ -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 {
index aec551fdb60d27d23ac773d8a89dbb56b4db2419..fa2c4ffb11526e7303ee70b510fce654a235dd16 100644 (file)
@@ -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 {}
 
index 26fd1c26ea7edd39f7351e32ea9bc47c69630f19..af902a009638bf22a97ada463d687b3ad7b0c0bc 100644 (file)
@@ -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);
index 5ab9499a61463210c3dbf68e1a1553c839e8f0b3..b38894ccfac3a4b4967d6363c2cd8835e2f642f9 100644 (file)
@@ -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))
index 7485fbb0b49087f640b80d8c16de2a406ef30eb5..5f7a4a2da2989d63519a3cad471d8638f6503399 100644 (file)
@@ -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))
index 60b4d988d680dab310394e04687887380c8c8dea..3709fd94eda3e7a8c35d15ba6fbfcab9435461aa 100644 (file)
@@ -199,6 +199,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
   //  global variables.
   return Result->invalidateRegions(RegionsToInvalidate, getOriginExpr(),
                                    BlockCount, getLocationContext(),
+                                   /*ResultsInPointerEscape*/ true,
                                    /*Symbols=*/0, this);
 }
 
index a4915c0dc0b115fcaa6f3c9f9c0d7a3ef258a343..9591f0cd2ec2bb56cf8d5722c25e4e4b0b446b25 100644 (file)
@@ -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);
 }
index efb4f7229f81231871718190e885329155dd207c..6b3394046384b14fdae856ed23f9935c564b0fa9 100644 (file)
@@ -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.
index 3b96cc899f5f40e909b6576e5aea4ef680128bb4..15662776d9eb92b1e398b770f650255e5f167d1f 100644 (file)
@@ -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);
   }
 
index 32eb56ca7350dc13d9635c60edba4a972d1f3309..9d66c16e73e6b72a97cb57c2830170de6629b553 100644 (file)
@@ -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),