Browse Source

[analyzer] This patch removes passing around of const-invalidation vs regular-invalidation info by passing around a datastructure that maps regions and symbols to the type of invalidation they experience. This simplifies the code and would allow to associate more different invalidation types in the future.
With this patch things like preserving contents of regions (either hi- or low-level ones) or processing of the only top-level region can be implemented easily without passing around extra parameters.

This patch is a first step towards adequate modeling of memcpy() by the CStringChecker checker and towards eliminating of majority of false-positives produced by the NewDeleteLeaks checker.

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

Anton Yartsev 12 years ago
parent
commit
da8d37ce42

+ 40 - 13
include/clang/StaticAnalyzer/Core/Checker.h

@@ -320,18 +320,33 @@ public:
 class PointerEscape {
 class PointerEscape {
   template <typename CHECKER>
   template <typename CHECKER>
   static ProgramStateRef
   static ProgramStateRef
-  _checkPointerEscape(void *checker,
+  _checkPointerEscape(void *Checker,
                      ProgramStateRef State,
                      ProgramStateRef State,
                      const InvalidatedSymbols &Escaped,
                      const InvalidatedSymbols &Escaped,
                      const CallEvent *Call,
                      const CallEvent *Call,
                      PointerEscapeKind Kind,
                      PointerEscapeKind Kind,
-                    bool IsConst) {
-    if (!IsConst)
-      return ((const CHECKER *)checker)->checkPointerEscape(State,
+                     RegionAndSymbolInvalidationTraits *ETraits) {
+
+    if (!ETraits)
+      return ((const CHECKER *)Checker)->checkPointerEscape(State,
                                                             Escaped,
                                                             Escaped,
                                                             Call,
                                                             Call,
                                                             Kind);
                                                             Kind);
-    return State;
+
+    InvalidatedSymbols RegularEscape;
+    for (InvalidatedSymbols::const_iterator I = Escaped.begin(), 
+                                            E = Escaped.end(); I != E; ++I)
+      if (!ETraits->hasTrait(*I,
+              RegionAndSymbolInvalidationTraits::TK_PreserveContents))
+        RegularEscape.insert(*I);
+
+    if (RegularEscape.empty())
+      return State;
+
+    return ((const CHECKER *)Checker)->checkPointerEscape(State,
+                                                          RegularEscape,
+                                                          Call,
+                                                          Kind);
   }
   }
 
 
 public:
 public:
@@ -346,18 +361,30 @@ public:
 class ConstPointerEscape {
 class ConstPointerEscape {
   template <typename CHECKER>
   template <typename CHECKER>
   static ProgramStateRef
   static ProgramStateRef
-  _checkConstPointerEscape(void *checker,
+  _checkConstPointerEscape(void *Checker,
                       ProgramStateRef State,
                       ProgramStateRef State,
                       const InvalidatedSymbols &Escaped,
                       const InvalidatedSymbols &Escaped,
                       const CallEvent *Call,
                       const CallEvent *Call,
                       PointerEscapeKind Kind,
                       PointerEscapeKind Kind,
-                      bool IsConst) {
-    if (IsConst)
-      return ((const CHECKER *)checker)->checkConstPointerEscape(State,
-                                                                 Escaped,
-                                                                 Call,
-                                                                 Kind);
-    return State;
+                      RegionAndSymbolInvalidationTraits *ETraits) {
+
+    if (!ETraits)
+      return State;
+
+    InvalidatedSymbols ConstEscape;
+    for (InvalidatedSymbols::const_iterator I = Escaped.begin(), 
+                                            E = Escaped.end(); I != E; ++I)
+      if (ETraits->hasTrait(*I,
+              RegionAndSymbolInvalidationTraits::TK_PreserveContents))
+        ConstEscape.insert(*I);
+
+    if (ConstEscape.empty())
+      return State;
+
+    return ((const CHECKER *)Checker)->checkConstPointerEscape(State,
+                                                               ConstEscape,
+                                                               Call,
+                                                               Kind);
   }
   }
 
 
 public:
 public:

+ 5 - 3
include/clang/StaticAnalyzer/Core/CheckerManager.h

@@ -365,14 +365,16 @@ public:
   /// \param Escaped The list of escaped symbols.
   /// \param Escaped The list of escaped symbols.
   /// \param Call The corresponding CallEvent, if the symbols escape as 
   /// \param Call The corresponding CallEvent, if the symbols escape as 
   ///        parameters to the given call.
   ///        parameters to the given call.
-  /// \param IsConst Specifies if the pointer is const.
+  /// \param Kind The reason of pointer escape.
+  /// \param ITraits Information about invalidation for a particular 
+  ///        region/symbol.
   /// \returns Checkers can modify the state by returning a new one.
   /// \returns Checkers can modify the state by returning a new one.
   ProgramStateRef 
   ProgramStateRef 
   runCheckersForPointerEscape(ProgramStateRef State,
   runCheckersForPointerEscape(ProgramStateRef State,
                               const InvalidatedSymbols &Escaped,
                               const InvalidatedSymbols &Escaped,
                               const CallEvent *Call,
                               const CallEvent *Call,
                               PointerEscapeKind Kind,
                               PointerEscapeKind Kind,
-                              bool IsConst = false);
+                             RegionAndSymbolInvalidationTraits *ITraits);
 
 
   /// \brief Run checkers for handling assumptions on symbolic values.
   /// \brief Run checkers for handling assumptions on symbolic values.
   ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state,
   ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state,
@@ -464,7 +466,7 @@ public:
                                      const InvalidatedSymbols &Escaped,
                                      const InvalidatedSymbols &Escaped,
                                      const CallEvent *Call,
                                      const CallEvent *Call,
                                      PointerEscapeKind Kind,
                                      PointerEscapeKind Kind,
-                                     bool IsConst)>
+                                     RegionAndSymbolInvalidationTraits *ITraits)>
       CheckPointerEscapeFunc;
       CheckPointerEscapeFunc;
   
   
   typedef CheckerFn<ProgramStateRef (ProgramStateRef,
   typedef CheckerFn<ProgramStateRef (ProgramStateRef,

+ 2 - 2
include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h

@@ -478,14 +478,14 @@ protected:
                                               SVal Loc, SVal Val);
                                               SVal Loc, SVal Val);
   /// Call PointerEscape callback when a value escapes as a result of
   /// Call PointerEscape callback when a value escapes as a result of
   /// region invalidation.
   /// region invalidation.
-  /// \param[in] IsConst Specifies that the pointer is const.
+  /// \param[in] ITraits Specifies invalidation traits for regions/symbols.
   ProgramStateRef notifyCheckersOfPointerEscape(
   ProgramStateRef notifyCheckersOfPointerEscape(
                             ProgramStateRef State,
                             ProgramStateRef State,
                             const InvalidatedSymbols *Invalidated,
                             const InvalidatedSymbols *Invalidated,
                             ArrayRef<const MemRegion *> ExplicitRegions,
                             ArrayRef<const MemRegion *> ExplicitRegions,
                             ArrayRef<const MemRegion *> Regions,
                             ArrayRef<const MemRegion *> Regions,
                             const CallEvent *Call,
                             const CallEvent *Call,
-                            bool IsConst);
+                            RegionAndSymbolInvalidationTraits &ITraits);
 
 
 public:
 public:
   // FIXME: 'tag' should be removed, and a LocationContext should be used
   // FIXME: 'tag' should be removed, and a LocationContext should be used

+ 31 - 0
include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h

@@ -1309,6 +1309,37 @@ private:
 inline ASTContext &MemRegion::getContext() const {
 inline ASTContext &MemRegion::getContext() const {
   return getMemRegionManager()->getContext();
   return getMemRegionManager()->getContext();
 }
 }
+
+//===----------------------------------------------------------------------===//
+// Means for storing region/symbol handling traits.
+//===----------------------------------------------------------------------===//
+
+/// Information about invalidation for a particular region/symbol.
+class RegionAndSymbolInvalidationTraits {
+  typedef unsigned char StorageTypeForKinds;
+  llvm::DenseMap<const MemRegion *, StorageTypeForKinds> MRTraitsMap;
+  llvm::DenseMap<SymbolRef, StorageTypeForKinds> SymTraitsMap;
+
+  typedef llvm::DenseMap<const MemRegion *, StorageTypeForKinds>::const_iterator
+      const_region_iterator;
+  typedef llvm::DenseMap<SymbolRef, StorageTypeForKinds>::const_iterator
+      const_symbol_iterator;
+
+public:
+  /// \brief Describes different invalidation traits.
+  enum InvalidationKinds {
+    /// Tells that a region's contents is not changed.
+    TK_PreserveContents = 0x1
+
+    // Do not forget to extend StorageTypeForKinds if number of traits exceed 
+    // the number of bits StorageTypeForKinds can store.
+  };
+
+  void setTrait(SymbolRef Sym, InvalidationKinds IK);
+  void setTrait(const MemRegion *MR, InvalidationKinds IK);
+  bool hasTrait(SymbolRef Sym, InvalidationKinds IK);
+  bool hasTrait(const MemRegion *MR, InvalidationKinds IK);
+};
   
   
 } // end GR namespace
 } // end GR namespace
 
 

+ 7 - 8
include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h

@@ -232,22 +232,21 @@ public:
   /// \param IS the set of invalidated symbols.
   /// \param IS the set of invalidated symbols.
   /// \param Call if non-null, the invalidated regions represent parameters to
   /// \param Call if non-null, the invalidated regions represent parameters to
   ///        the call and should be considered directly invalidated.
   ///        the call and should be considered directly invalidated.
-  /// \param ConstRegions the set of regions whose contents are accessible,
-  ///        even though the regions themselves should not be invalidated.
+  /// \param HTraits information about special handling for a particular 
+  ///        region/symbol.
   ProgramStateRef
   ProgramStateRef
   invalidateRegions(ArrayRef<const MemRegion *> Regions, const Expr *E,
   invalidateRegions(ArrayRef<const MemRegion *> Regions, const Expr *E,
                     unsigned BlockCount, const LocationContext *LCtx,
                     unsigned BlockCount, const LocationContext *LCtx,
                     bool CausesPointerEscape, InvalidatedSymbols *IS = 0,
                     bool CausesPointerEscape, InvalidatedSymbols *IS = 0,
                     const CallEvent *Call = 0,
                     const CallEvent *Call = 0,
-                    ArrayRef<const MemRegion *> ConstRegions =
-                      ArrayRef<const MemRegion *>()) const;
+                    RegionAndSymbolInvalidationTraits *HTraits = 0) const;
 
 
   ProgramStateRef
   ProgramStateRef
   invalidateRegions(ArrayRef<SVal> Regions, const Expr *E,
   invalidateRegions(ArrayRef<SVal> Regions, const Expr *E,
                     unsigned BlockCount, const LocationContext *LCtx,
                     unsigned BlockCount, const LocationContext *LCtx,
                     bool CausesPointerEscape, InvalidatedSymbols *IS = 0,
                     bool CausesPointerEscape, InvalidatedSymbols *IS = 0,
                     const CallEvent *Call = 0,
                     const CallEvent *Call = 0,
-                    ArrayRef<SVal> ConstRegions = ArrayRef<SVal>()) const;
+                    RegionAndSymbolInvalidationTraits *HTraits = 0) const;
 
 
   /// enterStackFrame - Returns the state for entry to the given stack frame,
   /// enterStackFrame - Returns the state for entry to the given stack frame,
   ///  preserving the current state.
   ///  preserving the current state.
@@ -425,9 +424,9 @@ private:
                         const Expr *E, unsigned BlockCount,
                         const Expr *E, unsigned BlockCount,
                         const LocationContext *LCtx,
                         const LocationContext *LCtx,
                         bool ResultsInSymbolEscape,
                         bool ResultsInSymbolEscape,
-                        InvalidatedSymbols &IS,
-                        const CallEvent *Call,
-                        ArrayRef<SVal> ConstValues) const;
+                        InvalidatedSymbols *IS,
+                        RegionAndSymbolInvalidationTraits *HTraits,
+                        const CallEvent *Call) const;
 };
 };
 
 
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//

+ 4 - 11
include/clang/StaticAnalyzer/Core/PathSensitive/Store.h

@@ -164,8 +164,6 @@ public:
   ///  the given regions. Optionally, invalidates non-static globals as well.
   ///  the given regions. Optionally, invalidates non-static globals as well.
   /// \param[in] store The initial store
   /// \param[in] store The initial store
   /// \param[in] Values The values to invalidate.
   /// \param[in] Values The values to invalidate.
-  /// \param[in] ConstValues The values to invalidate; these are known to be
-  ///   const, so only regions accesible from them should be invalidated.
   /// \param[in] E The current statement being evaluated. Used to conjure
   /// \param[in] E The current statement being evaluated. Used to conjure
   ///   symbols to mark the values of invalidated regions.
   ///   symbols to mark the values of invalidated regions.
   /// \param[in] Count The current block count. Used to conjure
   /// \param[in] Count The current block count. Used to conjure
@@ -174,13 +172,10 @@ public:
   ///   globals should get invalidated.
   ///   globals should get invalidated.
   /// \param[in,out] IS A set to fill with any symbols that are no longer
   /// \param[in,out] IS A set to fill with any symbols that are no longer
   ///   accessible. Pass \c NULL if this information will not be used.
   ///   accessible. Pass \c NULL if this information will not be used.
-  /// \param[in,out] ConstIS A set to fill with any symbols corresponding to
-  ///   the ConstValues.
+  /// \param[in] ITraits Information about invalidation for a particular 
+  ///   region/symbol.
   /// \param[in,out] InvalidatedTopLevel A vector to fill with regions
   /// \param[in,out] InvalidatedTopLevel A vector to fill with regions
-  ////  explicitely being invalidated. Pass \c NULL if this
-  ///   information will not be used.
-  /// \param[in,out] InvalidatedTopLevelConst A vector to fill with const 
-  ////  regions explicitely being invalidated. Pass \c NULL if this
+  ////  explicitly being invalidated. Pass \c NULL if this
   ///   information will not be used.
   ///   information will not be used.
   /// \param[in,out] Invalidated A vector to fill with any regions being
   /// \param[in,out] Invalidated A vector to fill with any regions being
   ///   invalidated. This should include any regions explicitly invalidated
   ///   invalidated. This should include any regions explicitly invalidated
@@ -188,14 +183,12 @@ public:
   ///   information will not be used.
   ///   information will not be used.
   virtual StoreRef invalidateRegions(Store store,
   virtual StoreRef invalidateRegions(Store store,
                                   ArrayRef<SVal> Values,
                                   ArrayRef<SVal> Values,
-                                  ArrayRef<SVal> ConstValues,
                                   const Expr *E, unsigned Count,
                                   const Expr *E, unsigned Count,
                                   const LocationContext *LCtx,
                                   const LocationContext *LCtx,
                                   const CallEvent *Call,
                                   const CallEvent *Call,
                                   InvalidatedSymbols &IS,
                                   InvalidatedSymbols &IS,
-                                  InvalidatedSymbols &ConstIS,
+                                  RegionAndSymbolInvalidationTraits &ITraits,
                                   InvalidatedRegions *InvalidatedTopLevel,
                                   InvalidatedRegions *InvalidatedTopLevel,
-                                  InvalidatedRegions *InvalidatedTopLevelConst,
                                   InvalidatedRegions *Invalidated) = 0;
                                   InvalidatedRegions *Invalidated) = 0;
 
 
   /// enterStackFrame - Let the StoreManager to do something when execution
   /// enterStackFrame - Let the StoreManager to do something when execution

+ 1 - 1
include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h

@@ -134,7 +134,7 @@ public:
                            ArrayRef<const MemRegion *> ExplicitRegions,
                            ArrayRef<const MemRegion *> ExplicitRegions,
                            ArrayRef<const MemRegion *> Regions,
                            ArrayRef<const MemRegion *> Regions,
                            const CallEvent *Call,
                            const CallEvent *Call,
-                           bool IsConst = false) = 0;
+                           RegionAndSymbolInvalidationTraits &HTraits) = 0;
 
 
   /// printState - Called by ProgramStateManager to print checker-specific data.
   /// printState - Called by ProgramStateManager to print checker-specific data.
   virtual void printState(raw_ostream &Out, ProgramStateRef State,
   virtual void printState(raw_ostream &Out, ProgramStateRef State,

+ 8 - 5
lib/StaticAnalyzer/Core/CallEvent.cpp

@@ -140,8 +140,8 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
                                              ProgramStateRef Orig) const {
                                              ProgramStateRef Orig) const {
   ProgramStateRef Result = (Orig ? Orig : getState());
   ProgramStateRef Result = (Orig ? Orig : getState());
 
 
-  SmallVector<SVal, 8> ConstValues;
   SmallVector<SVal, 8> ValuesToInvalidate;
   SmallVector<SVal, 8> ValuesToInvalidate;
+  RegionAndSymbolInvalidationTraits ETraits;
 
 
   getExtraInvalidatedValues(ValuesToInvalidate);
   getExtraInvalidatedValues(ValuesToInvalidate);
 
 
@@ -154,9 +154,12 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
     // Mark this region for invalidation.  We batch invalidate regions
     // Mark this region for invalidation.  We batch invalidate regions
     // below for efficiency.
     // below for efficiency.
     if (PreserveArgs.count(Idx))
     if (PreserveArgs.count(Idx))
-      ConstValues.push_back(getArgSVal(Idx));
-    else
-      ValuesToInvalidate.push_back(getArgSVal(Idx));
+      if (const MemRegion *MR = getArgSVal(Idx).getAsRegion())
+        ETraits.setTrait(MR->StripCasts(), 
+                        RegionAndSymbolInvalidationTraits::TK_PreserveContents);
+        // TODO: Factor this out + handle the lower level const pointers.
+
+    ValuesToInvalidate.push_back(getArgSVal(Idx));
   }
   }
 
 
   // Invalidate designated regions using the batch invalidation API.
   // Invalidate designated regions using the batch invalidation API.
@@ -165,7 +168,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
   return Result->invalidateRegions(ValuesToInvalidate, getOriginExpr(),
   return Result->invalidateRegions(ValuesToInvalidate, getOriginExpr(),
                                    BlockCount, getLocationContext(),
                                    BlockCount, getLocationContext(),
                                    /*CausedByPointerEscape*/ true,
                                    /*CausedByPointerEscape*/ true,
-                                   /*Symbols=*/0, this, ConstValues);
+                                   /*Symbols=*/0, this, &ETraits);
 }
 }
 
 
 ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
 ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,

+ 5 - 5
lib/StaticAnalyzer/Core/CheckerManager.cpp

@@ -487,10 +487,10 @@ CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
 /// \brief Run checkers to process symbol escape event.
 /// \brief Run checkers to process symbol escape event.
 ProgramStateRef
 ProgramStateRef
 CheckerManager::runCheckersForPointerEscape(ProgramStateRef State,
 CheckerManager::runCheckersForPointerEscape(ProgramStateRef State,
-                                           const InvalidatedSymbols &Escaped,
-                                           const CallEvent *Call,
-                                           PointerEscapeKind Kind,
-                                           bool IsConst) {
+                                   const InvalidatedSymbols &Escaped,
+                                   const CallEvent *Call,
+                                   PointerEscapeKind Kind,
+                                   RegionAndSymbolInvalidationTraits *ETraits) {
   assert((Call != NULL ||
   assert((Call != NULL ||
           (Kind != PSK_DirectEscapeOnCall &&
           (Kind != PSK_DirectEscapeOnCall &&
            Kind != PSK_IndirectEscapeOnCall)) &&
            Kind != PSK_IndirectEscapeOnCall)) &&
@@ -500,7 +500,7 @@ CheckerManager::runCheckersForPointerEscape(ProgramStateRef State,
       //  way), bail out.
       //  way), bail out.
       if (!State)
       if (!State)
         return NULL;
         return NULL;
-      State = PointerEscapeCheckers[i](State, Escaped, Call, Kind, IsConst);
+      State = PointerEscapeCheckers[i](State, Escaped, Call, Kind, ETraits);
     }
     }
   return State;
   return State;
 }
 }

+ 6 - 15
lib/StaticAnalyzer/Core/ExprEngine.cpp

@@ -1876,7 +1876,8 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State,
   State = getCheckerManager().runCheckersForPointerEscape(State,
   State = getCheckerManager().runCheckersForPointerEscape(State,
                                                           EscapedSymbols,
                                                           EscapedSymbols,
                                                           /*CallEvent*/ 0,
                                                           /*CallEvent*/ 0,
-                                                          PSK_EscapeOnBind);
+                                                          PSK_EscapeOnBind,
+                                                          0);
 
 
   return State;
   return State;
 }
 }
@@ -1887,7 +1888,7 @@ ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State,
     ArrayRef<const MemRegion *> ExplicitRegions,
     ArrayRef<const MemRegion *> ExplicitRegions,
     ArrayRef<const MemRegion *> Regions,
     ArrayRef<const MemRegion *> Regions,
     const CallEvent *Call,
     const CallEvent *Call,
-    bool IsConst) {
+    RegionAndSymbolInvalidationTraits &ITraits) {
   
   
   if (!Invalidated || Invalidated->empty())
   if (!Invalidated || Invalidated->empty())
     return State;
     return State;
@@ -1897,17 +1898,7 @@ ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State,
                                                            *Invalidated,
                                                            *Invalidated,
                                                            0,
                                                            0,
                                                            PSK_EscapeOther,
                                                            PSK_EscapeOther,
-                                                           IsConst);
-
-  // Note: Due to current limitations of RegionStore, we only process the top
-  // level const pointers correctly. The lower level const pointers are
-  // currently treated as non-const.
-  if (IsConst)
-    return getCheckerManager().runCheckersForPointerEscape(State,
-                                                        *Invalidated,
-                                                        Call,
-                                                        PSK_DirectEscapeOnCall,
-                                                        true);
+                                                           &ITraits);
 
 
   // If the symbols were invalidated by a call, we want to find out which ones 
   // 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.
   // were invalidated directly due to being arguments to the call.
@@ -1929,12 +1920,12 @@ ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State,
 
 
   if (!SymbolsDirectlyInvalidated.empty())
   if (!SymbolsDirectlyInvalidated.empty())
     State = getCheckerManager().runCheckersForPointerEscape(State,
     State = getCheckerManager().runCheckersForPointerEscape(State,
-        SymbolsDirectlyInvalidated, Call, PSK_DirectEscapeOnCall);
+        SymbolsDirectlyInvalidated, Call, PSK_DirectEscapeOnCall, &ITraits);
 
 
   // Notify about the symbols that get indirectly invalidated by the call.
   // Notify about the symbols that get indirectly invalidated by the call.
   if (!SymbolsIndirectlyInvalidated.empty())
   if (!SymbolsIndirectlyInvalidated.empty())
     State = getCheckerManager().runCheckersForPointerEscape(State,
     State = getCheckerManager().runCheckersForPointerEscape(State,
-        SymbolsIndirectlyInvalidated, Call, PSK_IndirectEscapeOnCall);
+        SymbolsIndirectlyInvalidated, Call, PSK_IndirectEscapeOnCall, &ITraits);
 
 
   return State;
   return State;
 }
 }

+ 42 - 0
lib/StaticAnalyzer/Core/MemRegion.cpp

@@ -1450,3 +1450,45 @@ const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const {
   }
   }
   return 0;
   return 0;
 }
 }
+
+//===----------------------------------------------------------------------===//
+// RegionAndSymbolInvalidationTraits
+//===----------------------------------------------------------------------===//
+
+void RegionAndSymbolInvalidationTraits::setTrait(SymbolRef Sym, 
+                                                 InvalidationKinds IK) {
+  SymTraitsMap[Sym] |= IK;
+}
+
+void RegionAndSymbolInvalidationTraits::setTrait(const MemRegion *MR, 
+                                                 InvalidationKinds IK) {
+  assert(MR);
+  if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
+    setTrait(SR->getSymbol(), IK);
+  else
+    MRTraitsMap[MR] |= IK;
+}
+
+bool RegionAndSymbolInvalidationTraits::hasTrait(SymbolRef Sym, 
+                                                 InvalidationKinds IK) {
+  const_symbol_iterator I = SymTraitsMap.find(Sym);
+  if (I != SymTraitsMap.end())
+    return I->second & IK;
+
+  return false;    
+}
+
+bool RegionAndSymbolInvalidationTraits::hasTrait(const MemRegion *MR,
+                                                 InvalidationKinds IK) {
+  if (!MR)
+    return false;
+
+  if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
+    return hasTrait(SR->getSymbol(), IK);
+
+  const_region_iterator I = MRTraitsMap.find(MR);
+  if (I != MRTraitsMap.end())
+    return I->second & IK;
+
+  return false;
+}

+ 35 - 55
lib/StaticAnalyzer/Core/ProgramState.cpp

@@ -137,48 +137,32 @@ typedef ArrayRef<SVal> ValueList;
 
 
 ProgramStateRef 
 ProgramStateRef 
 ProgramState::invalidateRegions(RegionList Regions,
 ProgramState::invalidateRegions(RegionList Regions,
-                                const Expr *E, unsigned Count,
-                                const LocationContext *LCtx,
-                                bool CausedByPointerEscape,
-                                InvalidatedSymbols *IS,
-                                const CallEvent *Call,
-                                RegionList ConstRegions) const {
+                             const Expr *E, unsigned Count,
+                             const LocationContext *LCtx,
+                             bool CausedByPointerEscape,
+                             InvalidatedSymbols *IS,
+                             const CallEvent *Call,
+                             RegionAndSymbolInvalidationTraits *ITraits) const {
   SmallVector<SVal, 8> Values;
   SmallVector<SVal, 8> Values;
   for (RegionList::const_iterator I = Regions.begin(),
   for (RegionList::const_iterator I = Regions.begin(),
                                   End = Regions.end(); I != End; ++I)
                                   End = Regions.end(); I != End; ++I)
     Values.push_back(loc::MemRegionVal(*I));
     Values.push_back(loc::MemRegionVal(*I));
 
 
-  SmallVector<SVal, 8> ConstValues;
-  for (RegionList::const_iterator I = ConstRegions.begin(),
-                                  End = ConstRegions.end(); I != End; ++I)
-    ConstValues.push_back(loc::MemRegionVal(*I));
-
-  if (!IS) {
-    InvalidatedSymbols invalidated;
-    return invalidateRegionsImpl(Values, E, Count, LCtx,
-                                 CausedByPointerEscape,
-                                 invalidated, Call, ConstValues);
-  }
   return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape,
   return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape,
-                               *IS, Call, ConstValues);
+                               IS, ITraits, Call);
 }
 }
 
 
 ProgramStateRef
 ProgramStateRef
 ProgramState::invalidateRegions(ValueList Values,
 ProgramState::invalidateRegions(ValueList Values,
-                                const Expr *E, unsigned Count,
-                                const LocationContext *LCtx,
-                                bool CausedByPointerEscape,
-                                InvalidatedSymbols *IS,
-                                const CallEvent *Call,
-                                ValueList ConstValues) const {
-  if (!IS) {
-    InvalidatedSymbols invalidated;
-    return invalidateRegionsImpl(Values, E, Count, LCtx,
-                                 CausedByPointerEscape,
-                                 invalidated, Call, ConstValues);
-  }
+                             const Expr *E, unsigned Count,
+                             const LocationContext *LCtx,
+                             bool CausedByPointerEscape,
+                             InvalidatedSymbols *IS,
+                             const CallEvent *Call,
+                             RegionAndSymbolInvalidationTraits *ITraits) const {
+
   return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape,
   return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape,
-                               *IS, Call, ConstValues);
+                               IS, ITraits, Call);
 }
 }
 
 
 ProgramStateRef
 ProgramStateRef
@@ -186,49 +170,45 @@ ProgramState::invalidateRegionsImpl(ValueList Values,
                                     const Expr *E, unsigned Count,
                                     const Expr *E, unsigned Count,
                                     const LocationContext *LCtx,
                                     const LocationContext *LCtx,
                                     bool CausedByPointerEscape,
                                     bool CausedByPointerEscape,
-                                    InvalidatedSymbols &IS,
-                                    const CallEvent *Call,
-                                    ValueList ConstValues) const {
+                                    InvalidatedSymbols *IS,
+                                    RegionAndSymbolInvalidationTraits *ITraits,
+                                    const CallEvent *Call) const {
   ProgramStateManager &Mgr = getStateManager();
   ProgramStateManager &Mgr = getStateManager();
   SubEngine* Eng = Mgr.getOwningEngine();
   SubEngine* Eng = Mgr.getOwningEngine();
   InvalidatedSymbols ConstIS;
   InvalidatedSymbols ConstIS;
 
 
+  InvalidatedSymbols Invalidated;
+  if (!IS)
+    IS = &Invalidated;
+
+  RegionAndSymbolInvalidationTraits ITraitsLocal;
+  if (!ITraits)
+    ITraits = &ITraitsLocal;
+
   if (Eng) {
   if (Eng) {
     StoreManager::InvalidatedRegions TopLevelInvalidated;
     StoreManager::InvalidatedRegions TopLevelInvalidated;
-    StoreManager::InvalidatedRegions TopLevelConstInvalidated;
     StoreManager::InvalidatedRegions Invalidated;
     StoreManager::InvalidatedRegions Invalidated;
     const StoreRef &newStore
     const StoreRef &newStore
-    = Mgr.StoreMgr->invalidateRegions(getStore(), Values, ConstValues,
-                                      E, Count, LCtx, Call,
-                                      IS, ConstIS,
-                                      &TopLevelInvalidated,
-                                      &TopLevelConstInvalidated,
+    = Mgr.StoreMgr->invalidateRegions(getStore(), Values, E, Count, LCtx, Call,
+                                      *IS, *ITraits, &TopLevelInvalidated,
                                       &Invalidated);
                                       &Invalidated);
 
 
     ProgramStateRef newState = makeWithStore(newStore);
     ProgramStateRef newState = makeWithStore(newStore);
 
 
     if (CausedByPointerEscape) {
     if (CausedByPointerEscape) {
-      newState = Eng->notifyCheckersOfPointerEscape(newState, &IS,
+      newState = Eng->notifyCheckersOfPointerEscape(newState, IS,
                                                     TopLevelInvalidated,
                                                     TopLevelInvalidated,
-                                                    Invalidated, Call);
-      if (!ConstValues.empty()) {
-        StoreManager::InvalidatedRegions Empty;
-        newState = Eng->notifyCheckersOfPointerEscape(newState, &ConstIS,
-                                                      TopLevelConstInvalidated,
-                                                      Empty, Call,
-                                                      true);
-      }
+                                                    Invalidated, Call, 
+                                                    *ITraits);
     }
     }
 
 
-    return Eng->processRegionChanges(newState, &IS,
-                                     TopLevelInvalidated, Invalidated,
-                                     Call);
+    return Eng->processRegionChanges(newState, IS, TopLevelInvalidated, 
+                                     Invalidated, Call);
   }
   }
 
 
   const StoreRef &newStore =
   const StoreRef &newStore =
-  Mgr.StoreMgr->invalidateRegions(getStore(), Values, ConstValues,
-                                  E, Count, LCtx, Call,
-                                  IS, ConstIS, NULL, NULL, NULL);
+  Mgr.StoreMgr->invalidateRegions(getStore(), Values, E, Count, LCtx, Call,
+                                  *IS, *ITraits, NULL, NULL);
   return makeWithStore(newStore);
   return makeWithStore(newStore);
 }
 }
 
 

+ 37 - 51
lib/StaticAnalyzer/Core/RegionStore.cpp

@@ -349,7 +349,6 @@ private:
   /// regions.
   /// regions.
   void populateWorkList(invalidateRegionsWorker &W,
   void populateWorkList(invalidateRegionsWorker &W,
                         ArrayRef<SVal> Values,
                         ArrayRef<SVal> Values,
-                        bool IsArrayOfConstRegions,
                         InvalidatedRegions *TopLevelRegions);
                         InvalidatedRegions *TopLevelRegions);
 
 
 public:
 public:
@@ -395,15 +394,13 @@ public:
 
 
   StoreRef invalidateRegions(Store store,
   StoreRef invalidateRegions(Store store,
                              ArrayRef<SVal> Values,
                              ArrayRef<SVal> Values,
-                             ArrayRef<SVal> ConstValues,
                              const Expr *E, unsigned Count,
                              const Expr *E, unsigned Count,
                              const LocationContext *LCtx,
                              const LocationContext *LCtx,
                              const CallEvent *Call,
                              const CallEvent *Call,
                              InvalidatedSymbols &IS,
                              InvalidatedSymbols &IS,
-                             InvalidatedSymbols &ConstIS,
+                             RegionAndSymbolInvalidationTraits &ITraits,
                              InvalidatedRegions *Invalidated,
                              InvalidatedRegions *Invalidated,
-                             InvalidatedRegions *InvalidatedTopLevel,
-                             InvalidatedRegions *InvalidatedTopLevelConst);
+                             InvalidatedRegions *InvalidatedTopLevel);
 
 
   bool scanReachableSymbols(Store S, const MemRegion *R,
   bool scanReachableSymbols(Store S, const MemRegion *R,
                             ScanReachableSymbols &Callbacks);
                             ScanReachableSymbols &Callbacks);
@@ -648,7 +645,7 @@ template <typename DERIVED>
 class ClusterAnalysis  {
 class ClusterAnalysis  {
 protected:
 protected:
   typedef llvm::DenseMap<const MemRegion *, const ClusterBindings *> ClusterMap;
   typedef llvm::DenseMap<const MemRegion *, const ClusterBindings *> ClusterMap;
-  typedef llvm::PointerIntPair<const MemRegion *, 1, bool> WorkListElement;
+  typedef const MemRegion * WorkListElement;
   typedef SmallVector<WorkListElement, 10> WorkList;
   typedef SmallVector<WorkListElement, 10> WorkList;
 
 
   llvm::SmallPtrSet<const ClusterBindings *, 16> Visited;
   llvm::SmallPtrSet<const ClusterBindings *, 16> Visited;
@@ -720,18 +717,17 @@ public:
     return true;
     return true;
   }
   }
 
 
-  bool AddToWorkList(const MemRegion *R, bool Flag = false) {
+  bool AddToWorkList(const MemRegion *R) {
     const MemRegion *BaseR = R->getBaseRegion();
     const MemRegion *BaseR = R->getBaseRegion();
-    return AddToWorkList(WorkListElement(BaseR, Flag), getCluster(BaseR));
+    return AddToWorkList(WorkListElement(BaseR), getCluster(BaseR));
   }
   }
 
 
   void RunWorkList() {
   void RunWorkList() {
     while (!WL.empty()) {
     while (!WL.empty()) {
       WorkListElement E = WL.pop_back_val();
       WorkListElement E = WL.pop_back_val();
-      const MemRegion *BaseR = E.getPointer();
+      const MemRegion *BaseR = E;
 
 
-      static_cast<DERIVED*>(this)->VisitCluster(BaseR, getCluster(BaseR),
-                                                E.getInt());
+      static_cast<DERIVED*>(this)->VisitCluster(BaseR, getCluster(BaseR));
     }
     }
   }
   }
 
 
@@ -951,7 +947,7 @@ class invalidateRegionsWorker : public ClusterAnalysis<invalidateRegionsWorker>
   unsigned Count;
   unsigned Count;
   const LocationContext *LCtx;
   const LocationContext *LCtx;
   InvalidatedSymbols &IS;
   InvalidatedSymbols &IS;
-  InvalidatedSymbols &ConstIS;
+  RegionAndSymbolInvalidationTraits &ITraits;
   StoreManager::InvalidatedRegions *Regions;
   StoreManager::InvalidatedRegions *Regions;
 public:
 public:
   invalidateRegionsWorker(RegionStoreManager &rm,
   invalidateRegionsWorker(RegionStoreManager &rm,
@@ -960,16 +956,15 @@ public:
                           const Expr *ex, unsigned count,
                           const Expr *ex, unsigned count,
                           const LocationContext *lctx,
                           const LocationContext *lctx,
                           InvalidatedSymbols &is,
                           InvalidatedSymbols &is,
-                          InvalidatedSymbols &inConstIS,
+                          RegionAndSymbolInvalidationTraits &ITraitsIn,
                           StoreManager::InvalidatedRegions *r,
                           StoreManager::InvalidatedRegions *r,
                           GlobalsFilterKind GFK)
                           GlobalsFilterKind GFK)
     : ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, GFK),
     : ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, GFK),
-      Ex(ex), Count(count), LCtx(lctx), IS(is), ConstIS(inConstIS), Regions(r){}
+      Ex(ex), Count(count), LCtx(lctx), IS(is), ITraits(ITraitsIn), Regions(r){}
 
 
   /// \param IsConst Specifies if the region we are invalidating is constant.
   /// \param IsConst Specifies if the region we are invalidating is constant.
   /// If it is, we invalidate all subregions, but not the base region itself.
   /// If it is, we invalidate all subregions, but not the base region itself.
-  void VisitCluster(const MemRegion *baseR, const ClusterBindings *C,
-                    bool IsConst);
+  void VisitCluster(const MemRegion *baseR, const ClusterBindings *C);
   void VisitBinding(SVal V);
   void VisitBinding(SVal V);
 };
 };
 }
 }
@@ -1000,14 +995,18 @@ void invalidateRegionsWorker::VisitBinding(SVal V) {
 }
 }
 
 
 void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
 void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
-                                           const ClusterBindings *C,
-                                           bool IsConst) {
+                                           const ClusterBindings *C) {
+
+  bool PreserveRegionsContents = 
+      ITraits.hasTrait(baseR, 
+                       RegionAndSymbolInvalidationTraits::TK_PreserveContents);
+
   if (C) {
   if (C) {
     for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I)
     for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I)
       VisitBinding(I.getData());
       VisitBinding(I.getData());
 
 
-    // Invalidate the contents of a non-const base region.
-    if (!IsConst)
+    // Invalidate regions contents.
+    if (!PreserveRegionsContents)
       B = B.remove(baseR);
       B = B.remove(baseR);
   }
   }
 
 
@@ -1039,18 +1038,11 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
   }
   }
 
 
   // Symbolic region?
   // Symbolic region?
-  if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR)) {
-    SymbolRef RegionSym = SR->getSymbol();
-
-    // Mark that symbol touched by the invalidation.
-    if (IsConst)
-      ConstIS.insert(RegionSym);
-    else
-      IS.insert(RegionSym);
-  }
+  if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
+    IS.insert(SR->getSymbol());
 
 
-  // Nothing else should be done for a const region.
-  if (IsConst)
+  // Nothing else should be done in the case when we preserve regions context.
+  if (PreserveRegionsContents)
     return;
     return;
 
 
   // Otherwise, we have a normal data region. Record that we touched the region.
   // Otherwise, we have a normal data region. Record that we touched the region.
@@ -1059,7 +1051,7 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
 
 
   if (isa<AllocaRegion>(baseR) || isa<SymbolicRegion>(baseR)) {
   if (isa<AllocaRegion>(baseR) || isa<SymbolicRegion>(baseR)) {
     // Invalidate the region by setting its default value to
     // Invalidate the region by setting its default value to
-    // conjured symbol. The type of the symbol is irrelavant.
+    // conjured symbol. The type of the symbol is irrelevant.
     DefinedOrUnknownSVal V =
     DefinedOrUnknownSVal V =
       svalBuilder.conjureSymbolVal(baseR, Ex, LCtx, Ctx.IntTy, Count);
       svalBuilder.conjureSymbolVal(baseR, Ex, LCtx, Ctx.IntTy, Count);
     B = B.addBinding(baseR, BindingKey::Default, V);
     B = B.addBinding(baseR, BindingKey::Default, V);
@@ -1081,7 +1073,7 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
 
 
   if (T->isStructureOrClassType()) {
   if (T->isStructureOrClassType()) {
     // Invalidate the region by setting its default value to
     // Invalidate the region by setting its default value to
-    // conjured symbol. The type of the symbol is irrelavant.
+    // conjured symbol. The type of the symbol is irrelevant.
     DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
     DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
                                                           Ctx.IntTy, Count);
                                                           Ctx.IntTy, Count);
     B = B.addBinding(baseR, BindingKey::Default, V);
     B = B.addBinding(baseR, BindingKey::Default, V);
@@ -1130,7 +1122,6 @@ RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K,
 
 
 void RegionStoreManager::populateWorkList(invalidateRegionsWorker &W,
 void RegionStoreManager::populateWorkList(invalidateRegionsWorker &W,
                                           ArrayRef<SVal> Values,
                                           ArrayRef<SVal> Values,
-                                          bool IsArrayOfConstRegions,
                                           InvalidatedRegions *TopLevelRegions) {
                                           InvalidatedRegions *TopLevelRegions) {
   for (ArrayRef<SVal>::iterator I = Values.begin(),
   for (ArrayRef<SVal>::iterator I = Values.begin(),
                                 E = Values.end(); I != E; ++I) {
                                 E = Values.end(); I != E; ++I) {
@@ -1145,7 +1136,7 @@ void RegionStoreManager::populateWorkList(invalidateRegionsWorker &W,
         // Note: the last argument is false here because these are
         // Note: the last argument is false here because these are
         // non-top-level regions.
         // non-top-level regions.
         if (const MemRegion *R = (*I).getAsRegion())
         if (const MemRegion *R = (*I).getAsRegion())
-          W.AddToWorkList(R, /*IsConst=*/ false);
+          W.AddToWorkList(R);
       }
       }
       continue;
       continue;
     }
     }
@@ -1153,7 +1144,7 @@ void RegionStoreManager::populateWorkList(invalidateRegionsWorker &W,
     if (const MemRegion *R = V.getAsRegion()) {
     if (const MemRegion *R = V.getAsRegion()) {
       if (TopLevelRegions)
       if (TopLevelRegions)
         TopLevelRegions->push_back(R);
         TopLevelRegions->push_back(R);
-      W.AddToWorkList(R, /*IsConst=*/ IsArrayOfConstRegions);
+      W.AddToWorkList(R);
       continue;
       continue;
     }
     }
   }
   }
@@ -1161,16 +1152,14 @@ void RegionStoreManager::populateWorkList(invalidateRegionsWorker &W,
 
 
 StoreRef
 StoreRef
 RegionStoreManager::invalidateRegions(Store store,
 RegionStoreManager::invalidateRegions(Store store,
-                                      ArrayRef<SVal> Values,
-                                      ArrayRef<SVal> ConstValues,
-                                      const Expr *Ex, unsigned Count,
-                                      const LocationContext *LCtx,
-                                      const CallEvent *Call,
-                                      InvalidatedSymbols &IS,
-                                      InvalidatedSymbols &ConstIS,
-                                      InvalidatedRegions *TopLevelRegions,
-                                      InvalidatedRegions *TopLevelConstRegions,
-                                      InvalidatedRegions *Invalidated) {
+                                     ArrayRef<SVal> Values,
+                                     const Expr *Ex, unsigned Count,
+                                     const LocationContext *LCtx,
+                                     const CallEvent *Call,
+                                     InvalidatedSymbols &IS,
+                                     RegionAndSymbolInvalidationTraits &ITraits,
+                                     InvalidatedRegions *TopLevelRegions,
+                                     InvalidatedRegions *Invalidated) {
   GlobalsFilterKind GlobalsFilter;
   GlobalsFilterKind GlobalsFilter;
   if (Call) {
   if (Call) {
     if (Call->isInSystemHeader())
     if (Call->isInSystemHeader())
@@ -1182,17 +1171,14 @@ RegionStoreManager::invalidateRegions(Store store,
   }
   }
 
 
   RegionBindingsRef B = getRegionBindings(store);
   RegionBindingsRef B = getRegionBindings(store);
-  invalidateRegionsWorker W(*this, StateMgr, B, Ex, Count, LCtx, IS, ConstIS,
+  invalidateRegionsWorker W(*this, StateMgr, B, Ex, Count, LCtx, IS, ITraits,
                             Invalidated, GlobalsFilter);
                             Invalidated, GlobalsFilter);
 
 
   // Scan the bindings and generate the clusters.
   // Scan the bindings and generate the clusters.
   W.GenerateClusters();
   W.GenerateClusters();
 
 
   // Add the regions to the worklist.
   // Add the regions to the worklist.
-  populateWorkList(W, Values, /*IsArrayOfConstRegions*/ false,
-                   TopLevelRegions);
-  populateWorkList(W, ConstValues, /*IsArrayOfConstRegions*/ true,
-                   TopLevelConstRegions);
+  populateWorkList(W, Values, TopLevelRegions);
 
 
   W.RunWorkList();
   W.RunWorkList();