forked from OSchip/llvm-project
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. llvm-svn: 110020
This commit is contained in:
parent
460ad41d6d
commit
fd91d27630
|
@ -261,6 +261,22 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// 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 @@ public:
|
|||
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;
|
||||
|
@ -286,31 +307,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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 @@ public:
|
|||
|
||||
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 @@ public:
|
|||
|
||||
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 @@ public:
|
|||
|
||||
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 @@ public:
|
|||
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 @@ class VarRegion : public DeclRegion {
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
|
||||
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 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
return Ex->getType();
|
||||
}
|
||||
|
||||
virtual RegionOffset getAsOffset() const {
|
||||
return RegionOffset(this, 0);
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const;
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
|
|
|
@ -74,7 +74,14 @@ private:
|
|||
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 @@ StoreManager *clang::CreateFlatStoreManager(GRStateManager &StMgr) {
|
|||
|
||||
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 @@ Store FlatStoreManager::Bind(Store store, Loc L, SVal val) {
|
|||
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 @@ SVal FlatStoreManager::ArrayToPointer(Loc Array) {
|
|||
|
||||
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::print(Store store, llvm::raw_ostream& Out,
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
|
|||
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 @@ RegionRawOffset ElementRegion::getAsRawOffset() const {
|
|||
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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -1146,7 +1146,7 @@ SVal RegionStoreManager::RetrieveElement(Store store,
|
|||
// 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 @@ Store RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V,
|
|||
|
||||
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);
|
||||
|
|
|
@ -711,8 +711,8 @@ SVal SimpleSValuator::EvalBinOpLL(const GRState *state,
|
|||
}
|
||||
|
||||
// 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()) {
|
||||
|
|
|
@ -139,7 +139,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
|
|||
// 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
|
||||
|
|
|
@ -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}}
|
||||
}
|
Loading…
Reference in New Issue