[cfe-commits] r110020 - in /cfe/trunk: include/clang/Checker/PathSensitive/MemRegion.h lib/Checker/FlatStore.cpp lib/Checker/MemRegion.cpp lib/Checker/RegionStore.cpp lib/Checker/SimpleSValuator.cpp lib/Checker/Store.cpp test/Analysis/flat-store.c

Zhongxing Xu xuzhongxing at gmail.com
Sun Aug 1 21:56:14 PDT 2010


Author: zhongxingxu
Date: Sun Aug  1 23:56:14 2010
New Revision: 110020

URL: http://llvm.org/viewvc/llvm-project?rev=110020&view=rev
Log:
Improve flat store: MemRegion::getAsOffset() computes a region's offset within
the top-level object. FlatStore now can bind and retrieve element and field
regions.
PR7297 is fixed by flat store.

Added:
    cfe/trunk/test/Analysis/flat-store.c
Modified:
    cfe/trunk/include/clang/Checker/PathSensitive/MemRegion.h
    cfe/trunk/lib/Checker/FlatStore.cpp
    cfe/trunk/lib/Checker/MemRegion.cpp
    cfe/trunk/lib/Checker/RegionStore.cpp
    cfe/trunk/lib/Checker/SimpleSValuator.cpp
    cfe/trunk/lib/Checker/Store.cpp

Modified: cfe/trunk/include/clang/Checker/PathSensitive/MemRegion.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/MemRegion.h?rev=110020&r1=110019&r2=110020&view=diff
==============================================================================
--- cfe/trunk/include/clang/Checker/PathSensitive/MemRegion.h (original)
+++ cfe/trunk/include/clang/Checker/PathSensitive/MemRegion.h Sun Aug  1 23:56:14 2010
@@ -261,6 +261,22 @@
   }
 };
 
+/// Represent a region's offset within the top level base region.
+class RegionOffset {
+  /// The base region.
+  const MemRegion *R;
+
+  /// The bit offset within the base region. It shouldn't be negative.
+  uint64_t Offset;
+
+public:
+  RegionOffset(const MemRegion *r) : R(r), Offset(0) {}
+  RegionOffset(const MemRegion *r, uint64_t off) : R(r), Offset(off) {}
+
+  const MemRegion *getRegion() const { return R; }
+  uint64_t getOffset() const { return Offset; }
+};
+
 /// SubRegion - A region that subsets another larger region.  Most regions
 ///  are subclasses of SubRegion.
 class SubRegion : public MemRegion {
@@ -277,6 +293,11 @@
     return UnknownVal();
   }
 
+  /// Compute the offset within the top level memory object.
+  virtual RegionOffset getAsOffset() const {
+    assert(0 && "unimplemented");
+  }
+
   MemRegionManager* getMemRegionManager() const;
 
   bool isSubRegionOf(const MemRegion* R) const;
@@ -287,31 +308,6 @@
 };
 
 //===----------------------------------------------------------------------===//
-// Auxillary data classes for use with MemRegions.
-//===----------------------------------------------------------------------===//
-
-class ElementRegion;
-
-class RegionRawOffset {
-private:
-  friend class ElementRegion;
-
-  const MemRegion *Region;
-  int64_t Offset;
-
-  RegionRawOffset(const MemRegion* reg, int64_t offset = 0)
-    : Region(reg), Offset(offset) {}
-
-public:
-  // FIXME: Eventually support symbolic offsets.
-  int64_t getByteOffset() const { return Offset; }
-  const MemRegion *getRegion() const { return Region; }
-
-  void dumpToStream(llvm::raw_ostream& os) const;
-  void dump() const;
-};
-
-//===----------------------------------------------------------------------===//
 // MemRegion subclasses.
 //===----------------------------------------------------------------------===//
 
@@ -335,6 +331,10 @@
 
   DefinedOrUnknownSVal getExtent(ValueManager& ValMgr) const;
 
+  virtual RegionOffset getAsOffset() const {
+    return RegionOffset(this, 0);
+  }
+
   void Profile(llvm::FoldingSetNodeID& ID) const;
 
   static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr* Ex,
@@ -551,6 +551,10 @@
 
   DefinedOrUnknownSVal getExtent(ValueManager& ValMgr) const;
 
+  virtual RegionOffset getAsOffset() const {
+    return RegionOffset(this, 0);
+  }
+
   void Profile(llvm::FoldingSetNodeID& ID) const;
 
   static void ProfileRegion(llvm::FoldingSetNodeID& ID,
@@ -587,6 +591,10 @@
 
   DefinedOrUnknownSVal getExtent(ValueManager& ValMgr) const;
 
+  virtual RegionOffset getAsOffset() const {
+    return RegionOffset(this, 0);
+  }
+
   bool isBoundable() const { return false; }
 
   void Profile(llvm::FoldingSetNodeID& ID) const {
@@ -619,6 +627,10 @@
     return C.getCanonicalType(CL->getType());
   }
 
+  virtual RegionOffset getAsOffset() const {
+    return RegionOffset(this, 0);
+  }
+
   bool isBoundable() const { return !CL->isFileScope(); }
 
   void Profile(llvm::FoldingSetNodeID& ID) const;
@@ -661,6 +673,10 @@
   VarRegion(const VarDecl* vd, const MemRegion* sReg)
     : DeclRegion(vd, sReg, VarRegionKind) {}
 
+  virtual RegionOffset getAsOffset() const {
+    return RegionOffset(this, 0);
+  }
+
   static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl* VD,
                             const MemRegion *superRegion) {
     DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind);
@@ -704,7 +720,11 @@
   QualType getValueType(ASTContext &C) const {
     return QualType(ThisPointerTy, 0);
   }
-  
+
+  virtual RegionOffset getAsOffset() const {
+    return RegionOffset(this, 0);
+  }
+
   void dumpToStream(llvm::raw_ostream& os) const;
   
   static bool classof(const MemRegion* R) {
@@ -734,6 +754,8 @@
 
   DefinedOrUnknownSVal getExtent(ValueManager& ValMgr) const;
 
+  virtual RegionOffset getAsOffset() const;
+
   static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl* FD,
                             const MemRegion* superRegion) {
     DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind);
@@ -766,6 +788,30 @@
     return R->getKind() == ObjCIvarRegionKind;
   }
 };
+//===----------------------------------------------------------------------===//
+// Auxillary data classes for use with MemRegions.
+//===----------------------------------------------------------------------===//
+
+class ElementRegion;
+
+class RegionRawOffset {
+private:
+  friend class ElementRegion;
+
+  const MemRegion *Region;
+  int64_t Offset;
+
+  RegionRawOffset(const MemRegion* reg, int64_t offset = 0)
+    : Region(reg), Offset(offset) {}
+
+public:
+  // FIXME: Eventually support symbolic offsets.
+  int64_t getByteOffset() const { return Offset; }
+  const MemRegion *getRegion() const { return Region; }
+
+  void dumpToStream(llvm::raw_ostream& os) const;
+  void dump() const;
+};
 
 class ElementRegion : public TypedRegion {
   friend class MemRegionManager;
@@ -795,8 +841,10 @@
   QualType getElementType() const {
     return ElementType;
   }
+  /// Compute the offset within the array. The array might also be a subobject.
+  RegionRawOffset getAsArrayOffset() const;
 
-  RegionRawOffset getAsRawOffset() const;
+  virtual RegionOffset getAsOffset() const;
 
   void dumpToStream(llvm::raw_ostream& os) const;
 
@@ -824,6 +872,10 @@
     return Ex->getType();
   }
 
+  virtual RegionOffset getAsOffset() const {
+    return RegionOffset(this, 0);
+  }
+
   void Profile(llvm::FoldingSetNodeID &ID) const;
 
   static bool classof(const MemRegion* R) {

Modified: cfe/trunk/lib/Checker/FlatStore.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/FlatStore.cpp?rev=110020&r1=110019&r2=110020&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/FlatStore.cpp (original)
+++ cfe/trunk/lib/Checker/FlatStore.cpp Sun Aug  1 23:56:14 2010
@@ -74,7 +74,14 @@
     return RegionBindings(static_cast<const RegionBindings::TreeTy*>(store));
   }
 
-  Interval RegionToInterval(const MemRegion *R);
+  class RegionInterval {
+  public:
+    const MemRegion *R;
+    Interval I;
+    RegionInterval(const MemRegion *r, uint64_t s, uint64_t e) : R(r), I(s, e){}
+  };
+
+  RegionInterval RegionToInterval(const MemRegion *R);
 
   SVal RetrieveRegionWithNoBinding(const MemRegion *R, QualType T);
 };
@@ -86,11 +93,14 @@
 
 SVal FlatStoreManager::Retrieve(Store store, Loc L, QualType T) {
   const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
-  Interval I = RegionToInterval(R);
+  RegionInterval RI = RegionToInterval(R);
+
+  assert(RI.R && "should handle regions with unknown interval");
+
   RegionBindings B = getRegionBindings(store);
-  const BindingVal *BV = B.lookup(R);
+  const BindingVal *BV = B.lookup(RI.R);
   if (BV) {
-    const SVal *V = BVFactory.Lookup(*BV, I);
+    const SVal *V = BVFactory.Lookup(*BV, RI.I);
     if (V)
       return *V;
     else
@@ -116,9 +126,10 @@
   if (V)
     BV = *V;
 
-  Interval I = RegionToInterval(R);
-  BV = BVFactory.Add(BV, I, val);
-  B = RBFactory.Add(B, R, BV);
+  RegionInterval RI = RegionToInterval(R);
+  assert(RI.R && "should handle regions with unknown interval");
+  BV = BVFactory.Add(BV, RI.I, val);
+  B = RBFactory.Add(B, RI.R, BV);
   return B.getRoot();
 }
 
@@ -139,7 +150,7 @@
 
 Store FlatStoreManager::BindDecl(Store store, const VarRegion *VR, 
                                  SVal initVal) {
-  return store;
+  return Bind(store, ValMgr.makeLoc(VR), initVal);
 }
 
 Store FlatStoreManager::BindDeclWithNoInit(Store store, const VarRegion *VR) {
@@ -170,15 +181,30 @@
 void FlatStoreManager::iterBindings(Store store, BindingsHandler& f) {
 }
 
-Interval FlatStoreManager::RegionToInterval(const MemRegion *R) { 
+FlatStoreManager::RegionInterval 
+FlatStoreManager::RegionToInterval(const MemRegion *R) { 
   switch (R->getKind()) {
   case MemRegion::VarRegionKind: {
     QualType T = cast<VarRegion>(R)->getValueType(Ctx);
     uint64_t Size = Ctx.getTypeSize(T);
-    return Interval(0, Size-1);
+    return RegionInterval(R, 0, Size-1);
   }
+
+  case MemRegion::ElementRegionKind: 
+  case MemRegion::FieldRegionKind: {
+    const TypedRegion *TR = cast<TypedRegion>(R);
+    RegionOffset Offset = TR->getAsOffset();
+    // We cannot compute offset for all ElementRegions, for example, elements
+    // with symbolic offsets.
+    if (!Offset.getRegion())
+      return RegionInterval(0, 0, 0);
+    uint64_t Start = Offset.getOffset();
+    uint64_t Size = Ctx.getTypeSize(TR->getValueType(Ctx));
+    return RegionInterval(Offset.getRegion(), Start, Start+Size);
+  }
+
   default:
     llvm_unreachable("Region kind unhandled.");
-    return Interval(0, 0);
+    return RegionInterval(0, 0, 0);
   }
 }

Modified: cfe/trunk/lib/Checker/MemRegion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/MemRegion.cpp?rev=110020&r1=110019&r2=110020&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/MemRegion.cpp (original)
+++ cfe/trunk/lib/Checker/MemRegion.cpp Sun Aug  1 23:56:14 2010
@@ -18,6 +18,7 @@
 #include "clang/Analysis/AnalysisContext.h"
 #include "clang/Analysis/Support/BumpVector.h"
 #include "clang/AST/CharUnits.h"
+#include "clang/AST/RecordLayout.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace clang;
@@ -785,7 +786,7 @@
   return true;
 }
 
-RegionRawOffset ElementRegion::getAsRawOffset() const {
+RegionRawOffset ElementRegion::getAsArrayOffset() const {
   CharUnits offset = CharUnits::Zero();
   const ElementRegion *ER = this;
   const MemRegion *superR = NULL;
@@ -827,6 +828,50 @@
   return RegionRawOffset(superR, offset.getQuantity());
 }
 
+RegionOffset ElementRegion::getAsOffset() const {
+  uint64_t Offset;
+  if (const nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Index)) {
+    int64_t i = CI->getValue().getSExtValue();
+    assert(i >= 0);
+    // We cannot compute offset for incomplete types.
+    if (!IsCompleteType(getContext(), ElementType))
+      return RegionOffset(0); 
+    
+    CharUnits Size = getContext().getTypeSizeInChars(ElementType);
+    Offset = i * Size.getQuantity() * 8;
+  } else
+    // We cannot compute offset for symbolic index.
+    return RegionOffset(0);
+
+  // Get the offset of the super region.
+  RegionOffset SOffset = cast<SubRegion>(superRegion)->getAsOffset();
+  if (!SOffset.getRegion())
+    return RegionOffset(0);
+  else
+    return RegionOffset(SOffset.getRegion(), SOffset.getOffset() + Offset);
+}
+
+RegionOffset FieldRegion::getAsOffset() const {
+  const RecordDecl *RD = getDecl()->getParent();
+  assert(RD->isDefinition());
+  // Get the field number.
+  unsigned idx = 0;
+  for (RecordDecl::field_iterator FI = RD->field_begin(), FE = RD->field_end();
+       FI != FE; ++FI, ++idx)
+    if (getDecl() == *FI)
+      break;
+
+  const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
+  // This is offset in bits.
+  uint64_t Offset = Layout.getFieldOffset(idx);
+
+  RegionOffset SOffset = cast<SubRegion>(superRegion)->getAsOffset();
+  if (!SOffset.getRegion())
+    return RegionOffset(0);
+  else
+    return RegionOffset(SOffset.getRegion(), SOffset.getOffset() + Offset);
+}
+
 //===----------------------------------------------------------------------===//
 // BlockDataRegion
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/Checker/RegionStore.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/RegionStore.cpp?rev=110020&r1=110019&r2=110020&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/RegionStore.cpp (original)
+++ cfe/trunk/lib/Checker/RegionStore.cpp Sun Aug  1 23:56:14 2010
@@ -1146,7 +1146,7 @@
   //   char *y = &x;
   //   return *y;
   // FIXME: This is a hack, and doesn't do anything really intelligent yet.
-  const RegionRawOffset &O = R->getAsRawOffset();
+  const RegionRawOffset &O = R->getAsArrayOffset();
   if (const TypedRegion *baseR = dyn_cast_or_null<TypedRegion>(O.getRegion())) {
     QualType baseT = baseR->getValueType(Ctx);
     if (baseT->isScalarType()) {
@@ -1608,7 +1608,7 @@
 
 BindingKey BindingKey::Make(const MemRegion *R, Kind k) {
   if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
-    const RegionRawOffset &O = ER->getAsRawOffset();
+    const RegionRawOffset &O = ER->getAsArrayOffset();
 
     if (O.getRegion())
       return BindingKey(O.getRegion(), O.getByteOffset(), k);

Modified: cfe/trunk/lib/Checker/SimpleSValuator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/SimpleSValuator.cpp?rev=110020&r1=110019&r2=110020&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/SimpleSValuator.cpp (original)
+++ cfe/trunk/lib/Checker/SimpleSValuator.cpp Sun Aug  1 23:56:14 2010
@@ -711,8 +711,8 @@
       }
 
       // If the element indexes aren't comparable, see if the raw offsets are.
-      RegionRawOffset LeftOffset = LeftER->getAsRawOffset();
-      RegionRawOffset RightOffset = RightER->getAsRawOffset();
+      RegionRawOffset LeftOffset = LeftER->getAsArrayOffset();
+      RegionRawOffset RightOffset = RightER->getAsArrayOffset();
 
       if (LeftOffset.getRegion() != NULL &&
           LeftOffset.getRegion() == RightOffset.getRegion()) {

Modified: cfe/trunk/lib/Checker/Store.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/Store.cpp?rev=110020&r1=110019&r2=110020&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/Store.cpp (original)
+++ cfe/trunk/lib/Checker/Store.cpp Sun Aug  1 23:56:14 2010
@@ -139,7 +139,7 @@
       // FIXME: Handle symbolic raw offsets.
 
       const ElementRegion *elementR = cast<ElementRegion>(R);
-      const RegionRawOffset &rawOff = elementR->getAsRawOffset();
+      const RegionRawOffset &rawOff = elementR->getAsArrayOffset();
       const MemRegion *baseR = rawOff.getRegion();
 
       // If we cannot compute a raw offset, throw up our hands and return

Added: cfe/trunk/test/Analysis/flat-store.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/flat-store.c?rev=110020&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/flat-store.c (added)
+++ cfe/trunk/test/Analysis/flat-store.c Sun Aug  1 23:56:14 2010
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=flat -verify %s
+#define FAIL ((void)*(char*)0)
+struct simple { int x; };
+
+void PR7297 () {
+  struct simple a;
+  struct simple *p = &a;
+  p->x = 5;
+  if (!p[0].x) FAIL; // no-warning
+  if (p[0].x) FAIL; // expected-warning {{null}}
+}





More information about the cfe-commits mailing list