]> granicus.if.org Git - clang/commitdiff
- constify some uses of MemRegion* (MemRegion should be immutable).
authorTed Kremenek <kremenek@apple.com>
Fri, 17 Oct 2008 20:28:54 +0000 (20:28 +0000)
committerTed Kremenek <kremenek@apple.com>
Fri, 17 Oct 2008 20:28:54 +0000 (20:28 +0000)
- Added new region "SymbolicRegion", which maps symbol values to the region domain.
- Enhanced BasicStore::getFieldLValue() to return a FieldRegion (using SymbolicRegion)
- Added some utility methods to GRState for fetch svals from the store.
- Fixed regression in CheckNSError (we weren't getting the value bound to the parameter)

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

include/clang/Analysis/PathSensitive/GRState.h
include/clang/Analysis/PathSensitive/MemRegion.h
include/clang/Analysis/PathSensitive/RValues.h
include/clang/Analysis/PathSensitive/Store.h
lib/Analysis/BasicObjCFoundationChecks.cpp
lib/Analysis/BasicStore.cpp
lib/Analysis/CFRefCount.cpp
lib/Analysis/CheckNSError.cpp
lib/Analysis/MemRegion.cpp
lib/Analysis/RegionStore.cpp

index 331c8301cdb5c1f4ef0fe01c3fcde39058322b66..cd0ae39f88d5c2e93b9c0b6afde49d2e70e02165 100644 (file)
@@ -425,6 +425,10 @@ public:
     return StoreMgr->GetSVal(St->getStore(), LV, T);
   }
   
+  SVal GetSVal(const GRState* St, const MemRegion* R) {
+    return StoreMgr->GetRegionSVal(St->getStore(), R);
+  }  
+  
   void SetSVal(GRState& St, Loc LV, SVal V) {
     St.St = StoreMgr->SetSVal(St.St, LV, V);
   }
@@ -522,6 +526,10 @@ public:
     return Mgr->GetSVal(St, LV, T);
   }
   
+  SVal GetSVal(const MemRegion* R) {
+    return Mgr->GetSVal(St, R);
+  }
+  
   GRStateRef SetSVal(Expr* Ex, SVal V, bool isBlkExpr, bool Invalidate) {
     return GRStateRef(Mgr->SetSVal(St, Ex, V, isBlkExpr, Invalidate), *Mgr);
   }
index a1e02b0e98835dccd8b85e2c3ccaa98b172ecb88..fddf40d2e954a7ae77cac422e0bde406929ad2f6 100644 (file)
 #ifndef LLVM_CLANG_ANALYSIS_MEMREGION_H
 #define LLVM_CLANG_ANALYSIS_MEMREGION_H
 
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Analysis/PathSensitive/SymbolManager.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/Support/Allocator.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclObjC.h"
 #include <string>
 
 namespace llvm { class raw_ostream; }
@@ -33,7 +34,7 @@ class MemRegionManager;
 /// MemRegion - The root abstract class for all memory regions.
 class MemRegion : public llvm::FoldingSetNode {
 public:
-  enum Kind { MemSpaceRegionKind,
+  enum Kind { MemSpaceRegionKind, SymbolicRegionKind,
               // Typed regions.
               BEG_TYPED_REGIONS,
               VarRegionKind, FieldRegionKind, ObjCIvarRegionKind,
@@ -48,7 +49,6 @@ protected:
 
 public:
   // virtual MemExtent getExtent(MemRegionManager& mrm) const = 0;
-  virtual const MemRegion* getSuperRegion() const = 0;
   virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0;
   
   std::string getString() const;
@@ -67,11 +67,6 @@ class MemSpaceRegion : public MemRegion {
 public:
   //RegionExtent getExtent() const { return UndefinedExtent(); }
 
-  const MemRegion* getSuperRegion() const {
-    return 0;
-  }
-    
-  //static void ProfileRegion(llvm::FoldingSetNodeID& ID);
   void Profile(llvm::FoldingSetNodeID& ID) const;
 
   static bool classof(const MemRegion* R) {
@@ -79,22 +74,57 @@ public:
   }
 };
 
-/// TypedRegion - An abstract class representing regions that are typed.
-class TypedRegion : public MemRegion {
+/// SubRegion - A region that subsets another larger region.  Most regions
+///  are subclasses of SubRegion.
+class SubRegion : public MemRegion {
 protected:
-  const MemRegion* superRegion;
-
-  TypedRegion(const MemRegion* sReg, Kind k)
-    : MemRegion(k), superRegion(sReg) {};
+  const MemRegion* superRegion;  
+  SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {}
   
 public:
-  virtual QualType getType() const = 0;
-  
-  // MemExtent getExtent(MemRegionManager& mrm) const;
   const MemRegion* getSuperRegion() const {
     return superRegion;
   }
   
+  static bool classof(const MemRegion* R) {
+    return R->getKind() > SymbolicRegionKind;
+  }
+};
+  
+/// SymbolicRegion - A special, "non-concrete" region. Unlike other region
+///  clases, SymbolicRegion represents a region that serves as an alias for
+///  either a real region, a NULL pointer, etc.  It essentially is used to
+///  map the concept of symbolic values into the domain of regions.  Symbolic
+///  regions do not need to be typed.
+class SymbolicRegion : public MemRegion {
+protected:
+  const SymbolID sym;
+
+public:
+  SymbolicRegion(const SymbolID s) : MemRegion(SymbolicRegionKind), sym(s) {}
+    
+  SymbolID getSymbol() const {
+    return sym;
+  }
+    
+  void Profile(llvm::FoldingSetNodeID& ID) const;
+  static void ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolID sym);
+  
+  void print(llvm::raw_ostream& os) const;
+  
+  static bool classof(const MemRegion* R) {
+    return R->getKind() == SymbolicRegionKind;
+  }
+};  
+
+/// TypedRegion - An abstract class representing regions that are typed.
+class TypedRegion : public SubRegion {
+protected:
+  TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {}
+  
+public:
+  virtual QualType getType() const = 0;
+    
   static bool classof(const MemRegion* R) {
     unsigned k = R->getKind();
     return k > BEG_TYPED_REGIONS && k < END_TYPED_REGIONS;
@@ -152,7 +182,7 @@ class DeclRegion : public TypedRegion {
 protected:
   const Decl* D;
 
-  DeclRegion(const Decl* d, MemRegion* sReg, Kind k)
+  DeclRegion(const Decl* d, const MemRegion* sReg, Kind k)
     : TypedRegion(sReg, k), D(d) {}
 
   static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D,
@@ -165,7 +195,7 @@ public:
 class VarRegion : public DeclRegion {
   friend class MemRegionManager;
   
-  VarRegion(const VarDecl* vd, MemRegion* sReg)
+  VarRegion(const VarDecl* vd, const MemRegion* sReg)
     : DeclRegion(vd, sReg, VarRegionKind) {}
 
   static void ProfileRegion(llvm::FoldingSetNodeID& ID, VarDecl* VD,
@@ -187,7 +217,7 @@ public:
 class FieldRegion : public DeclRegion {
   friend class MemRegionManager;
 
-  FieldRegion(const FieldDecl* fd, MemRegion* sReg)
+  FieldRegion(const FieldDecl* fd, const MemRegion* sReg)
     : DeclRegion(fd, sReg, FieldRegionKind) {}
 
   static void ProfileRegion(llvm::FoldingSetNodeID& ID, FieldDecl* FD,
@@ -208,7 +238,7 @@ class ObjCIvarRegion : public DeclRegion {
   
   friend class MemRegionManager;
   
-  ObjCIvarRegion(const ObjCIvarDecl* ivd, MemRegion* sReg)
+  ObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* sReg)
     : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {}
 
   static void ProfileRegion(llvm::FoldingSetNodeID& ID, ObjCIvarDecl* ivd,
@@ -260,10 +290,13 @@ public:
   /// memory space.
   MemSpaceRegion* getUnknownRegion();
   
+  /// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
+  SymbolicRegion* getSymbolicRegion(const SymbolID sym);
+  
   /// getVarRegion - Retrieve or create the memory region associated with
   ///  a specified VarDecl.  'superRegion' corresponds to the containing
   ///  memory region, and 'off' is the offset within the containing region.
-  VarRegion* getVarRegion(const VarDecl* vd, MemRegion* superRegion);
+  VarRegion* getVarRegion(const VarDecl* vd, const MemRegion* superRegion);
   
   VarRegion* getVarRegion(const VarDecl* vd) {
     return getVarRegion(vd, vd->hasLocalStorage() ? getStackRegion() 
@@ -274,14 +307,14 @@ public:
   ///  a specified FieldDecl.  'superRegion' corresponds to the containing
   ///  memory region (which typically represents the memory representing
   ///  a structure or class).
-  FieldRegion* getFieldRegion(const FieldDecl* fd, MemRegion* superRegion);
+  FieldRegion* getFieldRegion(const FieldDecl* fd, const MemRegion* superRegion);
   
   /// getObjCIvarRegion - Retrieve or create the memory region associated with
   ///   a specified Objective-c instance variable.  'superRegion' corresponds
   ///   to the containing region (which typically represents the Objective-C
   ///   object).
   ObjCIvarRegion* getObjCIvarRegion(const ObjCIvarDecl* ivd,
-                                    MemRegion* superRegion);
+                                    const MemRegion* superRegion);
 
   AnonPointeeRegion* getAnonPointeeRegion(const VarDecl* d);
 
index c1ee0e0e9002a4dddddbfd184587045a6f8a60bd..3466b9b0017c43f9c61634dae91bf8bbfd431176 100644 (file)
@@ -331,10 +331,15 @@ class MemRegionVal : public Loc {
 public:
   MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {}
 
-  MemRegion* getRegion() const {
+  const MemRegion* getRegion() const {
     return static_cast<MemRegion*>(Data);
   }
   
+  template <typename REGION>
+  const REGION* getRegionAs() const {
+    return llvm::dyn_cast<REGION>(getRegion());
+  }  
+  
   inline bool operator==(const MemRegionVal& R) const {
     return getRegion() == R.getRegion();
   }
index 3acb789a24f8f35f713a49a8cda56d22428bf64b..b6d4be3b66dfdd51f94511c0c41b9a8a6266db3f 100644 (file)
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_ANALYSIS_STORE_H
 
 #include "clang/Analysis/PathSensitive/RValues.h"
+#include "clang/Analysis/PathSensitive/MemRegion.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/DenseSet.h"
@@ -31,8 +32,6 @@ class LiveVariables;
 class Stmt;
 class Expr;
 class ObjCIvarDecl;
-class MemRegion;
-class MemRegionManager;
 
 class StoreManager {
 public:
@@ -40,7 +39,12 @@ public:
   typedef llvm::DenseSet<SymbolID>          DeadSymbolsTy;
   
   virtual ~StoreManager() {}
-  virtual SVal GetSVal(Store St, Loc LV, QualType T = QualType()) = 0;
+  virtual SVal GetSVal(Store St, Loc LV, QualType T = QualType()) = 0;  
+
+  virtual SVal GetRegionSVal(Store St, const MemRegion* R) {
+    return GetSVal(St, loc::MemRegionVal(R));
+  }
+  
   virtual Store SetSVal(Store St, Loc LV, SVal V) = 0;
   virtual Store Remove(Store St, Loc LV) = 0;
   virtual Store getInitialStore() = 0;
index 8e322189e628e6ca2834ea50d5d4fabb59a976a8..96a7ea1c1682794ae7c8af5ffdec68610641def9 100644 (file)
@@ -367,7 +367,7 @@ public:
   
 private:
   
-  void AddError(TypedRegion* R, Expr* Ex, ExplodedNode<GRState> *N,
+  void AddError(const TypedRegion* R, Expr* Ex, ExplodedNode<GRState> *N,
                 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);  
 };
 } // end anonymous namespace
@@ -503,7 +503,7 @@ bool AuditCFNumberCreate::Audit(ExplodedNode<GRState>* N,GRStateManager&){
   if (!LV)
     return false;
   
-  TypedRegion* R = dyn_cast<TypedRegion>(LV->getRegion());
+  const TypedRegion* R = dyn_cast<TypedRegion>(LV->getRegion());
   if (!R)
     return false;
   
@@ -530,7 +530,7 @@ bool AuditCFNumberCreate::Audit(ExplodedNode<GRState>* N,GRStateManager&){
   return SourceSize < TargetSize;
 }
 
-void AuditCFNumberCreate::AddError(TypedRegion* R, Expr* Ex,
+void AuditCFNumberCreate::AddError(const TypedRegion* R, Expr* Ex,
                                    ExplodedNode<GRState> *N,
                                    uint64_t SourceSize, uint64_t TargetSize,
                                    uint64_t NumberKind) {
index 7998ef4613f36c8b9619aa243d4e84350b4ddc66..e1220ce674da8a4f5366a037b09bfd4158a78c36 100644 (file)
@@ -90,7 +90,41 @@ SVal BasicStoreManager::getLValueIvar(const GRState* St, const ObjCIvarDecl* D,
   
 SVal BasicStoreManager::getLValueField(const GRState* St, const FieldDecl* D,
                                        SVal Base) {
-  return UnknownVal();
+
+  if (Base.isUnknownOrUndef())
+    return Base;
+  
+  Loc BaseL = cast<Loc>(Base);  
+  const MemRegion* BaseR = 0;
+  
+  switch(BaseL.getSubKind()) {
+    case loc::SymbolValKind:
+      BaseR = MRMgr.getSymbolicRegion(cast<loc::SymbolVal>(&BaseL)->getSymbol());
+      break;
+      
+    case loc::GotoLabelKind:
+    case loc::FuncValKind:
+      // Technically we can get here if people do funny things with casts.
+      return UndefinedVal();
+
+    case loc::MemRegionKind:
+      BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
+      break;
+      
+    case loc::ConcreteIntKind:
+    case loc::StringLiteralValKind:
+      // While these seem funny, this can happen through casts.
+      // FIXME: What we should return is the field offset.  For example,
+      //  add the field offset to the integer value.  That way funny things
+      //  like this work properly:  &(((struct foo *) 0xa)->f)
+      return Base;
+
+    default:
+      assert ("Unhandled Base.");
+      return Base;
+  }
+  
+  return loc::MemRegionVal(MRMgr.getFieldRegion(D, BaseR));
 }
 
 SVal BasicStoreManager::getLValueElement(const GRState* St, SVal Base,
@@ -108,7 +142,7 @@ SVal BasicStoreManager::GetSVal(Store St, Loc LV, QualType T) {
   switch (LV.getSubKind()) {
 
     case loc::MemRegionKind: {
-      VarRegion* R =
+      const VarRegion* R =
         dyn_cast<VarRegion>(cast<loc::MemRegionVal>(LV).getRegion());
       
       if (!R)
@@ -145,7 +179,7 @@ SVal BasicStoreManager::GetSVal(Store St, Loc LV, QualType T) {
 Store BasicStoreManager::SetSVal(Store store, Loc LV, SVal V) {    
   switch (LV.getSubKind()) {      
     case loc::MemRegionKind: {
-      VarRegion* R =
+      const VarRegion* R =
         dyn_cast<VarRegion>(cast<loc::MemRegionVal>(LV).getRegion());
       
       if (!R)
@@ -165,8 +199,8 @@ Store BasicStoreManager::SetSVal(Store store, Loc LV, SVal V) {
 Store BasicStoreManager::Remove(Store store, Loc LV) {
   switch (LV.getSubKind()) {
     case loc::MemRegionKind: {
-      VarRegion* R =
-      dyn_cast<VarRegion>(cast<loc::MemRegionVal>(LV).getRegion());
+      const VarRegion* R =
+        dyn_cast<VarRegion>(cast<loc::MemRegionVal>(LV).getRegion());
       
       if (!R)
         return store;
index 9d632314b2dd8e8653ae8af6fab0068a0a63dab5..e720096aaf71165db2f467299399866107ed1099 100644 (file)
@@ -1513,7 +1513,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
           state = state.remove<RefBindings>(Sym);
         }
         
-        TypedRegion* R = dyn_cast<TypedRegion>(MR->getRegion());
+        const TypedRegion* R = dyn_cast<TypedRegion>(MR->getRegion());
         if (R) {
           // Set the value of the variable to be a conjured symbol.
           unsigned Count = Builder.getCurrentBlockCount();
@@ -1717,7 +1717,7 @@ void CFRefCount::EvalStore(ExplodedNodeSet<GRState>& Dst,
   if (!isa<loc::MemRegionVal>(TargetLV))
     escapes = true;
   else {
-    MemRegion* R = cast<loc::MemRegionVal>(TargetLV).getRegion();
+    const MemRegion* R = cast<loc::MemRegionVal>(TargetLV).getRegion();
     escapes = !Eng.getStateManager().hasStackStorage(R);
   }
   
index 38d32a731dd97f2d441f7f5a7da9339fa25a406f..f76b601e2d5a9e1f07e3455c86b0b646aeb5a4f3 100644 (file)
@@ -216,7 +216,11 @@ void NSErrorCheck::CheckParamDeref(VarDecl* Param, GRStateRef rootState,
                                    GRExprEngine& Eng, GRBugReporter& BR,
                                    bool isNSErrorWarning) {
   
-  SVal ParamSVal = rootState.GetLValue(Param);
+  SVal ParamL = rootState.GetLValue(Param);
+  const MemRegion* ParamR = cast<loc::MemRegionVal>(ParamL).getRegionAs<VarRegion>();
+  assert (ParamR && "Parameters always have VarRegions.");
+  SVal ParamSVal = rootState.GetSVal(ParamR);
+  
 
   // FIXME: For now assume that ParamSVal is symbolic.  We need to generalize
   // this later.
index 747d2f681816ffa11ca8e4efb5476a0d7b36b544..97a4fbc295085c025048fc769a4270b5b6aaaa35 100644 (file)
@@ -56,6 +56,15 @@ void DeclRegion::Profile(llvm::FoldingSetNodeID& ID) const {
   DeclRegion::ProfileRegion(ID, D, superRegion, getKind());
 }
 
+void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolID sym) {
+  ID.AddInteger((unsigned) MemRegion::SymbolicRegionKind);
+  ID.AddInteger(sym.getNumber());
+}
+
+void SymbolicRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  SymbolicRegion::ProfileRegion(ID, sym);
+}
+
 //===----------------------------------------------------------------------===//
 // Region pretty-printing.
 //===----------------------------------------------------------------------===//
@@ -75,6 +84,10 @@ void VarRegion::print(llvm::raw_ostream& os) const {
   os << cast<VarDecl>(D)->getName();
 }
 
+void SymbolicRegion::print(llvm::raw_ostream& os) const {
+  os << "$" << sym.getNumber();
+}
+
 //===----------------------------------------------------------------------===//
 // MemRegionManager methods.
 //===----------------------------------------------------------------------===//
@@ -106,7 +119,7 @@ MemSpaceRegion* MemRegionManager::getUnknownRegion() {
 }
 
 VarRegion* MemRegionManager::getVarRegion(const VarDecl* d,
-                                          MemRegion* superRegion) {
+                                          const MemRegion* superRegion) {
   llvm::FoldingSetNodeID ID;
   DeclRegion::ProfileRegion(ID, d, superRegion, MemRegion::VarRegionKind);
   
@@ -123,8 +136,27 @@ VarRegion* MemRegionManager::getVarRegion(const VarDecl* d,
   return R;
 }
 
+/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
+SymbolicRegion* MemRegionManager::getSymbolicRegion(const SymbolID sym) {
+  
+  llvm::FoldingSetNodeID ID;
+  SymbolicRegion::ProfileRegion(ID, sym);
+  
+  void* InsertPos;
+  MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
+  SymbolicRegion* R = cast_or_null<SymbolicRegion>(data);
+  
+  if (!R) {
+    R = (SymbolicRegion*) A.Allocate<SymbolicRegion>();
+    new (R) SymbolicRegion(sym);
+    Regions.InsertNode(R, InsertPos);
+  }
+  
+  return R;  
+}
+
 FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl* d,
-                                              MemRegion* superRegion) {
+                                              const MemRegion* superRegion) {
   llvm::FoldingSetNodeID ID;
   DeclRegion::ProfileRegion(ID, d, superRegion, MemRegion::FieldRegionKind);
   
@@ -141,8 +173,9 @@ FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl* d,
   return R;
 }
 
-ObjCIvarRegion* MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d,
-                                                    MemRegion* superRegion) {
+ObjCIvarRegion*
+MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d,
+                                    const MemRegion* superRegion) {
   llvm::FoldingSetNodeID ID;
   DeclRegion::ProfileRegion(ID, d, superRegion, MemRegion::ObjCIvarRegionKind);
   
@@ -181,11 +214,20 @@ AnonPointeeRegion* MemRegionManager::getAnonPointeeRegion(const VarDecl* d) {
 }
 
 bool MemRegionManager::hasStackStorage(const MemRegion* R) {
+  const SubRegion* SR = dyn_cast<SubRegion>(R);
+
+  // Only subregions can have stack storage.
+  if (!SR)
+    return false;
+  
   MemSpaceRegion* S = getStackRegion();
   
-  while (R) {
-    if (R == S) return true;
-    R = R->getSuperRegion();
+  while (SR) {
+    R = SR->getSuperRegion();
+    if (R == S)
+      return true;
+    
+    SR = dyn_cast<SubRegion>(R);    
   }
   
   return false;
index 6757f43ae1062b5ca4819e2f82b38fcb57bbf69e..48706ce8054405819989b4439a5cc313aae8653d 100644 (file)
@@ -52,7 +52,7 @@ public:
 Store RegionStoreManager::SetSVal(Store store, Loc LV, SVal V) {
   assert(LV.getSubKind() == loc::MemRegionKind);
 
-  MemRegion* R = cast<loc::MemRegionVal>(LV).getRegion();
+  const MemRegion* R = cast<loc::MemRegionVal>(LV).getRegion();
   
   if (!R)
     return store;