]> granicus.if.org Git - clang/commitdiff
Refine MemRegions for blocks. Add a new region called
authorTed Kremenek <kremenek@apple.com>
Wed, 25 Nov 2009 23:53:07 +0000 (23:53 +0000)
committerTed Kremenek <kremenek@apple.com>
Wed, 25 Nov 2009 23:53:07 +0000 (23:53 +0000)
'BlockDataRegion' to distinguish between the code associated with a
block (which is represented by 'BlockTextRegion') and an instance of a
block, which includes both code and data.  'BlockDataRegion' has an
associated LocationContext, which can be used to eventually model the
lifetime of a block object once LocationContexts can represent scopes
(and iterations around a loop, etc.).

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

include/clang/Analysis/PathSensitive/MemRegion.h
include/clang/Analysis/PathSensitive/ValueManager.h
lib/Analysis/CFRefCount.cpp
lib/Analysis/GRExprEngine.cpp
lib/Analysis/MemRegion.cpp
lib/Analysis/RegionStore.cpp
lib/Analysis/ValueManager.cpp

index df9caedefc0d851a43eb2c981108691a1b4df0a3..9a361501ceae1c24d4b2ca3f1acaafcb7256cf70 100644 (file)
@@ -50,6 +50,7 @@ public:
               BEG_TYPED_REGIONS,
                FunctionTextRegionKind,
                BlockTextRegionKind,
+               BlockDataRegionKind,
                CompoundLiteralRegionKind,
                StringRegionKind, ElementRegionKind,
                // Decl Regions.
@@ -286,6 +287,11 @@ public:
   
   
 /// BlockTextRegion - A region that represents code texts of blocks (closures).
+///  Blocks are represented with two kinds of regions.  BlockTextRegions
+///  represent the "code", while BlockDataRegions represent instances of blocks,
+///  which correspond to "code+data".  The distinction is important, because
+///  like a closure a block captures the values of externally referenced
+///  variables.
 class BlockTextRegion : public CodeTextRegion {
   const BlockDecl *BD;
   CanQualType locTy;
@@ -312,6 +318,37 @@ public:
     return R->getKind() == BlockTextRegionKind;
   }
 };
+  
+/// BlockDataRegion - A region that represents a block instance.
+///  Blocks are represented with two kinds of regions.  BlockTextRegions
+///  represent the "code", while BlockDataRegions represent instances of blocks,
+///  which correspond to "code+data".  The distinction is important, because
+///  like a closure a block captures the values of externally referenced
+///  variables.
+/// BlockDataRegion - A region that represents code texts of blocks (closures).
+class BlockDataRegion : public SubRegion {
+  const BlockTextRegion *BC;
+  const LocationContext *LC;
+public:  
+  BlockDataRegion(const BlockTextRegion *bc, 
+                  const LocationContext *lc,
+                  const MemRegion *sreg)
+  : SubRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc) {}
+
+  const BlockTextRegion *getCodeRegion() const { return BC; }
+    
+  virtual void dumpToStream(llvm::raw_ostream& os) const;
+    
+  void Profile(llvm::FoldingSetNodeID& ID) const;
+    
+  static void ProfileRegion(llvm::FoldingSetNodeID& ID,
+                            const BlockTextRegion *BC,
+                            const LocationContext *LC, const MemRegion *);
+    
+  static bool classof(const MemRegion* R) {
+    return R->getKind() == BlockDataRegionKind;
+  }
+};
 
 /// SymbolicRegion - A special, "non-concrete" region. Unlike other region
 ///  clases, SymbolicRegion represents a region that serves as an alias for
@@ -694,7 +731,8 @@ public:
 
   FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD);
   BlockTextRegion *getBlockTextRegion(const BlockDecl *BD, CanQualType locTy);
-
+  BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc,
+                                      const LocationContext *lc);
 
   template <typename RegionTy, typename A1>
   RegionTy* getRegion(const A1 a1);
@@ -705,6 +743,10 @@ public:
   template <typename RegionTy, typename A1, typename A2>
   RegionTy* getRegion(const A1 a1, const A2 a2);
 
+  template <typename RegionTy, typename A1, typename A2>
+  RegionTy* getSubRegion(const A1 a1, const A2 a2,
+                         const MemRegion* superRegion);
+
   bool isGlobalsRegion(const MemRegion* R) {
     assert(R);
     return R == globals;
@@ -783,6 +825,25 @@ RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) {
 
   return R;
 }
+  
+template <typename RegionTy, typename A1, typename A2>
+RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2,
+                                         const MemRegion *superRegion) {
+  
+  llvm::FoldingSetNodeID ID;
+  RegionTy::ProfileRegion(ID, a1, a2, superRegion);
+  void* InsertPos;
+  RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
+                                                                   InsertPos));
+  
+  if (!R) {
+    R = (RegionTy*) A.Allocate<RegionTy>();
+    new (R) RegionTy(a1, a2, superRegion);
+    Regions.InsertNode(R, InsertPos);
+  }
+  
+  return R;
+}
 
 //===----------------------------------------------------------------------===//
 // Traits for constructing regions.
index 66d431586424a3e8ca6a5fc9c63d5d1d9297f5e2..ef4e069ce8e8667304ee0e627058047d226f936a 100644 (file)
@@ -115,7 +115,8 @@ public:
 
   DefinedSVal getFunctionPointer(const FunctionDecl *FD);
   
-  DefinedSVal getBlockPointer(const BlockDecl *BD, CanQualType locTy);
+  DefinedSVal getBlockPointer(const BlockDecl *BD, CanQualType locTy,
+                              const LocationContext *LC);
 
   NonLoc makeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals) {
     return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals));
index 10d07762dbf1d86b2cb9d3d51a7682c8fb6f4dfb..06aa6bd2791f63696e216f6881efbb3653c83a64 100644 (file)
@@ -3002,7 +3002,7 @@ void CFRefCount::EvalCall(ExplodedNodeSet& Dst,
   // FIXME: Better support for blocks.  For now we stop tracking anything
   // that is passed to blocks.
   // FIXME: Need to handle variables that are "captured" by the block.
-  if (dyn_cast_or_null<BlockTextRegion>(L.getAsRegion())) {
+  if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) {
     Summ = Summaries.getPersistentStopSummary();
   }
   else {
index cb3f68b41df558b13b240a5c97a3eaa39039c8e2..12e9ba88648f11ee0be909313dff84e85cf96deb 100644 (file)
@@ -1107,7 +1107,9 @@ void GRExprEngine::VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred,
   ExplodedNodeSet Tmp;
   
   CanQualType T = getContext().getCanonicalType(BE->getType());
-  SVal V = ValMgr.getBlockPointer(BE->getBlockDecl(), T);
+  SVal V = ValMgr.getBlockPointer(BE->getBlockDecl(), T,
+                                  Pred->getLocationContext());
+
   MakeNode(Tmp, BE, Pred, GetState(Pred)->BindExpr(BE, V),
            ProgramPoint::PostLValueKind);
  
index 8b4c7a6a24078f525743ab6c2f60b30761b70f51..430ec238c8db21d00ce97eed50ae7c7f8861094e 100644 (file)
@@ -148,6 +148,19 @@ void BlockTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
   BlockTextRegion::ProfileRegion(ID, BD, locTy, superRegion);
 }
 
+void BlockDataRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+                                    const BlockTextRegion *BC,
+                                    const LocationContext *LC,
+                                    const MemRegion *) {
+  ID.AddInteger(MemRegion::BlockDataRegionKind);
+  ID.AddPointer(BC);
+  ID.AddPointer(LC);
+}
+
+void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  BlockDataRegion::ProfileRegion(ID, BC, LC, NULL);
+}
+
 //===----------------------------------------------------------------------===//
 // Region pretty-printing.
 //===----------------------------------------------------------------------===//
@@ -176,9 +189,14 @@ void FunctionTextRegion::dumpToStream(llvm::raw_ostream& os) const {
 }
 
 void BlockTextRegion::dumpToStream(llvm::raw_ostream& os) const {
-  os << "block{" << (void*) this << '}';
+  os << "block_code{" << (void*) this << '}';
 }
 
+void BlockDataRegion::dumpToStream(llvm::raw_ostream& os) const {
+  os << "block_data{" << BC << '}';
+}
+
+
 void CompoundLiteralRegion::dumpToStream(llvm::raw_ostream& os) const {
   // FIXME: More elaborate pretty-printing.
   os << "{ " << (void*) CL <<  " }";
@@ -274,6 +292,18 @@ VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
   return getRegion<VarRegion>(D, LC);
 }
 
+BlockDataRegion *MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC,
+                                                      const LocationContext *LC)
+{
+  // FIXME: Once we implement scope handling, we will need to properly lookup
+  // 'D' to the proper LocationContext.  For now, just strip down to the
+  // StackFrame.
+  while (!isa<StackFrameContext>(LC))
+    LC = LC->getParent();
+  
+  return getSubRegion<BlockDataRegion>(BC, LC, getStackRegion());
+}
+
 CompoundLiteralRegion*
 MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL) {
   return getRegion<CompoundLiteralRegion>(CL);
index 16a4690f95ad1ce44df11e471e60b18ea88caf3a..deb6c0785254e7943a0e169721312030b4958135 100644 (file)
@@ -714,6 +714,7 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
 
     case MemRegion::FunctionTextRegionKind:
     case MemRegion::BlockTextRegionKind:
+    case MemRegion::BlockDataRegionKind:
       // Technically this can happen if people do funny things with casts.
       return UnknownVal();
 
@@ -860,6 +861,7 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
 
     case MemRegion::FunctionTextRegionKind:
     case MemRegion::BlockTextRegionKind:
+    case MemRegion::BlockDataRegionKind:
       // Technically this can happen if people do funny things with casts.
       return UnknownVal();
 
index 37df44360226e192434eeb7f143073681bc6f192..22a821149dbb33259c57b54a7eb0d5c8df1f2566 100644 (file)
@@ -142,9 +142,11 @@ DefinedSVal ValueManager::getFunctionPointer(const FunctionDecl* FD) {
   return loc::MemRegionVal(R);
 }
 
-DefinedSVal ValueManager::getBlockPointer(const BlockDecl *BD,
-                                          CanQualType locTy) {
-  CodeTextRegion *R  = MemMgr.getBlockTextRegion(BD, locTy);
-  return loc::MemRegionVal(R);
+DefinedSVal ValueManager::getBlockPointer(const BlockDecl *D,
+                                          CanQualType locTy,
+                                          const LocationContext *LC) {
+  BlockTextRegion *BC = MemMgr.getBlockTextRegion(D, locTy);
+  BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, LC);
+  return loc::MemRegionVal(BD);
 }