}
};
+/// 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 {
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;
}
};
-//===----------------------------------------------------------------------===//
-// 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.
//===----------------------------------------------------------------------===//
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,
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,
DefinedOrUnknownSVal getExtent(ValueManager& ValMgr) const;
+ virtual RegionOffset getAsOffset() const {
+ return RegionOffset(this, 0);
+ }
+
bool isBoundable() const { return false; }
void Profile(llvm::FoldingSetNodeID& ID) const {
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;
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);
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) {
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);
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;
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;
return Ex->getType();
}
+ virtual RegionOffset getAsOffset() const {
+ return RegionOffset(this, 0);
+ }
+
void Profile(llvm::FoldingSetNodeID &ID) const;
static bool classof(const MemRegion* R) {
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);
};
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
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();
}
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) {
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);
}
}
#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;
return true;
}
-RegionRawOffset ElementRegion::getAsRawOffset() const {
+RegionRawOffset ElementRegion::getAsArrayOffset() const {
CharUnits offset = CharUnits::Zero();
const ElementRegion *ER = this;
const MemRegion *superR = NULL;
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
//===----------------------------------------------------------------------===//
// 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()) {
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);
}
// 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()) {
// 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
--- /dev/null
+// 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}}
+}