Lazy bingding for region-store manager.

* Now Bind() methods take and return GRState* because binding could
  also alter GDM.
* No variables are initialized except those declared with initial
  values.
* failed C test cases are due to bugs in RemoveDeadBindings(),
which removes constraints that is still alive. This will be fixed in later
patch.
* default value of array and struct regions will be implemented in later patch.

llvm-svn: 61274
This commit is contained in:
Zhongxing Xu 2008-12-20 06:32:12 +00:00
parent ab66b87f7f
commit af7415ffb1
14 changed files with 375 additions and 459 deletions

View File

@ -336,15 +336,24 @@ public:
typedef StoreManager::DeadSymbolsTy DeadSymbolsTy;
const GRState* BindDecl(const GRState* St, const VarDecl* VD, SVal* IVal,
unsigned Count);
const GRState* BindDecl(const GRState* St, const VarDecl* VD, SVal IVal) {
// Store manager should return a persistent state.
return StoreMgr->BindDecl(St, VD, IVal);
}
const GRState* BindDeclWithNoInit(const GRState* St, const VarDecl* VD) {
// Store manager should return a persistent state.
return StoreMgr->BindDeclWithNoInit(St, VD);
}
/// BindCompoundLiteral - Return the state that has the bindings currently
/// in 'state' plus the bindings for the CompoundLiteral. 'R' is the region
/// for the compound literal and 'BegInit' and 'EndInit' represent an
/// array of initializer values.
const GRState* BindCompoundLiteral(const GRState* state,
const CompoundLiteralExpr* CL, SVal V);
const GRState* BindCompoundLiteral(const GRState* St,
const CompoundLiteralExpr* CL, SVal V) {
return StoreMgr->BindCompoundLiteral(St, CL, V);
}
const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc,
const LiveVariables& Liveness,
@ -468,12 +477,10 @@ public:
return StoreMgr->GetRegionSVal(state, R);
}
void BindLoc(GRState& St, Loc LV, SVal V) {
St.St = StoreMgr->Bind(St.St, LV, V);
const GRState* BindLoc(const GRState* St, Loc LV, SVal V) {
return StoreMgr->Bind(St, LV, V);
}
const GRState* BindLoc(const GRState* St, Loc LV, SVal V);
void Unbind(GRState& St, Loc LV) {
St.St = StoreMgr->Remove(St.St, LV);
}
@ -482,6 +489,9 @@ public:
const GRState* getPersistentState(GRState& Impl);
// MakeStateWithStore - get a persistent state with the new store.
const GRState* MakeStateWithStore(const GRState* St, Store store);
bool isEqual(const GRState* state, Expr* Ex, const llvm::APSInt& V);
bool isEqual(const GRState* state, Expr* Ex, uint64_t);
@ -502,6 +512,14 @@ public:
GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Set(st->get<T>(), K, V, C)));
}
template <typename T>
const GRState* add(const GRState* st,
typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::context_type C) {
return addGDM(st, GRStateTrait<T>::GDMIndex(),
GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Add(st->get<T>(), K, C)));
}
template <typename T>
const GRState* remove(const GRState* st,
typename GRStateTrait<T>::key_type K,
@ -587,14 +605,12 @@ public:
return GRStateRef(Mgr->BindExpr(St, Ex, V, Invalidate), *Mgr);
}
GRStateRef BindDecl(const VarDecl* VD, SVal* InitVal, unsigned Count) {
return GRStateRef(Mgr->BindDecl(St, VD, InitVal, Count), *Mgr);
GRStateRef BindDecl(const VarDecl* VD, SVal InitVal) {
return GRStateRef(Mgr->BindDecl(St, VD, InitVal), *Mgr);
}
GRStateRef BindLoc(Loc LV, SVal V) {
GRState StImpl = *St;
Mgr->BindLoc(StImpl, LV, V);
return GRStateRef(Mgr->getPersistentState(StImpl), *Mgr);
return GRStateRef(Mgr->BindLoc(St, LV, V), *Mgr);
}
GRStateRef BindLoc(SVal LV, SVal V) {
@ -645,6 +661,11 @@ public:
return GRStateRef(Mgr->set<T>(St, K, E, get_context<T>()), *Mgr);
}
template<typename T>
GRStateRef add(typename GRStateTrait<T>::key_type K) {
return GRStateRef(Mgr->add<T>(St, K, get_context<T>()), *Mgr);
}
template<typename T>
GRStateRef remove(typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::context_type C) {
@ -658,7 +679,7 @@ public:
template<typename T>
bool contains(typename GRStateTrait<T>::key_type key) const {
return St->contains(key);
return St->contains<T>(key);
}
// Lvalue methods.

View File

@ -467,6 +467,12 @@ public:
return R == globals;
}
/// onStack - check if the region is allocated on the stack.
bool onStack(const MemRegion* R);
/// onHeap - check if the region is allocated on the heap, usually by malloc.
bool onHeap(const MemRegion* R);
/// getAllocaRegion - Retrieve a region associated with a call to alloca().
AllocaRegion* getAllocaRegion(const Expr* Ex, unsigned Cnt);

View File

@ -72,6 +72,12 @@ public:
return !(*this == R);
}
/// MakeSymbolValue - make a unique symbol value for the region R according to
/// its kind. R should be a scalar region. The symbol value T has the same
/// type as R's rvalue type.
static SVal MakeSymbolValue(SymbolManager& SymMgr, const MemRegion* R,
QualType T);
static SVal GetSymbolValue(SymbolManager& SymMgr, VarDecl *D);
static SVal getSymbolValue(SymbolManager& SymMgr, const MemRegion* R,
const llvm::APSInt* Idx, QualType T);
@ -171,6 +177,8 @@ public:
// Utility methods to create NonLocs.
static NonLoc MakeVal(SymbolRef sym);
static NonLoc MakeVal(BasicValueFactory& BasicVals, unsigned X,
bool isUnsigned);
@ -213,6 +221,8 @@ public:
static Loc MakeVal(AddrLabelExpr* E);
static Loc MakeVal(SymbolRef sym);
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
return V->getBaseKind() == LocKind;

View File

@ -50,14 +50,17 @@ public:
return Retrieve(state, loc::MemRegionVal(R));
}
virtual Store Bind(Store St, Loc LV, SVal V) = 0;
virtual Store Remove(Store St, Loc LV) = 0;
/// Bind value V to location L.
virtual const GRState* Bind(const GRState* St, Loc L, SVal V) = 0;
virtual Store Remove(Store St, Loc L) = 0;
/// BindCompoundLiteral - Return the store that has the bindings currently
/// in 'store' plus the bindings for the CompoundLiteral. 'R' is the region
/// for the compound literal and 'BegInit' and 'EndInit' represent an
/// array of initializer values.
virtual Store BindCompoundLiteral(Store store, const CompoundLiteralExpr* CL,
virtual const GRState* BindCompoundLiteral(const GRState* St,
const CompoundLiteralExpr* CL,
SVal V) = 0;
virtual Store getInitialStore() = 0;
@ -112,8 +115,11 @@ public:
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots,
LiveSymbolsTy& LSymbols, DeadSymbolsTy& DSymbols) = 0;
virtual Store BindDecl(Store store, const VarDecl* VD, SVal* InitVal,
unsigned Count) = 0;
virtual const GRState* BindDecl(const GRState* St, const VarDecl* VD,
SVal InitVal) = 0;
virtual const GRState* BindDeclWithNoInit(const GRState* St,
const VarDecl* VD) = 0;
virtual const GRState* setExtent(const GRState* St,
const MemRegion* R, SVal Extent) {

View File

@ -104,15 +104,15 @@ public:
};
class SymbolDataParmVar : public SymbolData {
ParmVarDecl *VD;
const ParmVarDecl *VD;
public:
SymbolDataParmVar(SymbolRef MySym, ParmVarDecl* vd)
SymbolDataParmVar(SymbolRef MySym, const ParmVarDecl* vd)
: SymbolData(ParmKind, MySym), VD(vd) {}
ParmVarDecl* getDecl() const { return VD; }
const ParmVarDecl* getDecl() const { return VD; }
static void Profile(llvm::FoldingSetNodeID& profile, ParmVarDecl* VD) {
static void Profile(llvm::FoldingSetNodeID& profile, const ParmVarDecl* VD) {
profile.AddInteger((unsigned) ParmKind);
profile.AddPointer(VD);
}
@ -128,15 +128,15 @@ public:
};
class SymbolDataGlobalVar : public SymbolData {
VarDecl *VD;
const VarDecl *VD;
public:
SymbolDataGlobalVar(SymbolRef MySym, VarDecl* vd) :
SymbolDataGlobalVar(SymbolRef MySym, const VarDecl* vd) :
SymbolData(GlobalKind, MySym), VD(vd) {}
VarDecl* getDecl() const { return VD; }
const VarDecl* getDecl() const { return VD; }
static void Profile(llvm::FoldingSetNodeID& profile, VarDecl* VD) {
static void Profile(llvm::FoldingSetNodeID& profile, const VarDecl* VD) {
profile.AddInteger((unsigned) GlobalKind);
profile.AddPointer(VD);
}
@ -276,7 +276,9 @@ public:
~SymbolManager();
SymbolRef getSymbol(VarDecl* D);
/// Make a unique symbol for MemRegion R according to its kind.
SymbolRef getSymbol(const MemRegion* R);
SymbolRef getSymbol(const VarDecl* D);
SymbolRef getElementSymbol(const MemRegion* R, const llvm::APSInt* Idx);
SymbolRef getFieldSymbol(const MemRegion* R, const FieldDecl* D);
SymbolRef getConjuredSymbol(Stmt* E, QualType T, unsigned VisitCount);

View File

@ -39,7 +39,14 @@ public:
~BasicStoreManager() {}
SVal Retrieve(const GRState *state, Loc LV, QualType T);
Store Bind(Store St, Loc LV, SVal V);
const GRState* Bind(const GRState* St, Loc L, SVal V) {
Store store = St->getStore();
store = BindInternal(store, L, V);
return StateMgr.MakeStateWithStore(St, store);
}
Store BindInternal(Store St, Loc LV, SVal V);
Store Remove(Store St, Loc LV);
Store getInitialStore();
MemRegionManager& getRegionManager() { return MRMgr; }
@ -49,9 +56,10 @@ public:
return loc::MemRegionVal(MRMgr.getVarRegion(VD));
}
Store BindCompoundLiteral(Store store, const CompoundLiteralExpr* CL,
const GRState* BindCompoundLiteral(const GRState* St,
const CompoundLiteralExpr* CL,
SVal V) {
return store;
return St;
}
SVal getLValueVar(const GRState* St, const VarDecl* VD);
@ -89,7 +97,25 @@ public:
void iterBindings(Store store, BindingsHandler& f);
Store BindDecl(Store store, const VarDecl* VD, SVal* InitVal, unsigned Count);
const GRState* BindDecl(const GRState* St, const VarDecl* VD, SVal InitVal) {
Store store = St->getStore();
store = BindDeclInternal(store, VD, &InitVal);
return StateMgr.MakeStateWithStore(St, store);
}
const GRState* BindDeclWithNoInit(const GRState* St, const VarDecl* VD) {
Store store = St->getStore();
store = BindDeclInternal(store, VD, 0);
return StateMgr.MakeStateWithStore(St, store);
}
const GRState* BindDecl(const GRState* St, const VarDecl* VD) {
Store store = St->getStore();
store = BindDeclInternal(store, VD, 0);
return StateMgr.MakeStateWithStore(St, store);
}
Store BindDeclInternal(Store store, const VarDecl* VD, SVal* InitVal);
static inline VarBindingsTy GetVarBindings(Store store) {
return VarBindingsTy(static_cast<const VarBindingsTy::TreeTy*>(store));
@ -286,7 +312,7 @@ SVal BasicStoreManager::Retrieve(const GRState* state, Loc LV, QualType T) {
return UnknownVal();
}
Store BasicStoreManager::Bind(Store store, Loc LV, SVal V) {
Store BasicStoreManager::BindInternal(Store store, Loc LV, SVal V) {
switch (LV.getSubKind()) {
case loc::MemRegionKind: {
const VarRegion* R =
@ -421,7 +447,7 @@ Store BasicStoreManager::getInitialStore() {
SelfRegion = MRMgr.getObjCObjectRegion(MD->getClassInterface(),
MRMgr.getHeapRegion());
St = Bind(St, loc::MemRegionVal(MRMgr.getVarRegion(PD)),
St = BindInternal(St, loc::MemRegionVal(MRMgr.getVarRegion(PD)),
loc::MemRegionVal(SelfRegion));
}
}
@ -441,15 +467,15 @@ Store BasicStoreManager::getInitialStore() {
? SVal::GetSymbolValue(StateMgr.getSymbolManager(), VD)
: UndefinedVal();
St = Bind(St, loc::MemRegionVal(MRMgr.getVarRegion(VD)), X);
St = BindInternal(St, loc::MemRegionVal(MRMgr.getVarRegion(VD)), X);
}
}
}
return St;
}
Store BasicStoreManager::BindDecl(Store store, const VarDecl* VD,
SVal* InitVal, unsigned Count) {
Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD,
SVal* InitVal) {
BasicValueFactory& BasicVals = StateMgr.getBasicVals();
@ -479,16 +505,16 @@ Store BasicStoreManager::BindDecl(Store store, const VarDecl* VD,
if (!InitVal) {
QualType T = VD->getType();
if (Loc::IsLocType(T))
store = Bind(store, getLoc(VD),
store = BindInternal(store, getLoc(VD),
loc::ConcreteInt(BasicVals.getValue(0, T)));
else if (T->isIntegerType())
store = Bind(store, getLoc(VD),
store = BindInternal(store, getLoc(VD),
nonloc::ConcreteInt(BasicVals.getValue(0, T)));
else {
// assert(0 && "ignore other types of variables");
}
} else {
store = Bind(store, getLoc(VD), *InitVal);
store = BindInternal(store, getLoc(VD), *InitVal);
}
}
} else {
@ -496,7 +522,7 @@ Store BasicStoreManager::BindDecl(Store store, const VarDecl* VD,
QualType T = VD->getType();
if (Loc::IsLocType(T) || T->isIntegerType()) {
SVal V = InitVal ? *InitVal : UndefinedVal();
store = Bind(store, getLoc(VD), V);
store = BindInternal(store, getLoc(VD), V);
}
}

View File

@ -1812,6 +1812,7 @@ void GRExprEngine::VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst) {
const GRState* St = GetState(*I);
unsigned Count = Builder->getCurrentBlockCount();
// Decls without InitExpr are not initialized explicitly.
if (InitEx) {
SVal InitVal = GetSVal(St, InitEx);
QualType T = VD->getType();
@ -1829,11 +1830,9 @@ void GRExprEngine::VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst) {
}
}
St = StateMgr.BindDecl(St, VD, &InitVal, Count);
}
else
St = StateMgr.BindDecl(St, VD, 0, Count);
St = StateMgr.BindDecl(St, VD, InitVal);
} else
St = StateMgr.BindDeclWithNoInit(St, VD);
// Check if 'VD' is a VLA and if so check if has a non-zero size.
QualType T = getContext().getCanonicalType(VD->getType());

View File

@ -59,51 +59,6 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
LSymbols, DSymbols);
}
const GRState* GRStateManager::BindLoc(const GRState* St, Loc LV, SVal V) {
Store OldStore = St->getStore();
Store NewStore = StoreMgr->Bind(OldStore, LV, V);
if (NewStore == OldStore)
return St;
GRState NewSt = *St;
NewSt.St = NewStore;
return getPersistentState(NewSt);
}
const GRState* GRStateManager::BindDecl(const GRState* St, const VarDecl* VD,
SVal* InitVal, unsigned Count) {
Store OldStore = St->getStore();
Store NewStore = StoreMgr->BindDecl(OldStore, VD, InitVal, Count);
if (NewStore == OldStore)
return St;
GRState NewSt = *St;
NewSt.St = NewStore;
return getPersistentState(NewSt);
}
/// BindCompoundLiteral - Return the store that has the bindings currently
/// in 'store' plus the bindings for the CompoundLiteral. 'R' is the region
/// for the compound literal and 'BegInit' and 'EndInit' represent an
/// array of initializer values.
const GRState*
GRStateManager::BindCompoundLiteral(const GRState* state,
const CompoundLiteralExpr* CL, SVal ILV) {
Store oldStore = state->getStore();
Store newStore = StoreMgr->BindCompoundLiteral(oldStore, CL, ILV);
if (newStore == oldStore)
return state;
GRState newState = *state;
newState.St = newStore;
return getPersistentState(newState);
}
const GRState* GRStateManager::Unbind(const GRState* St, Loc LV) {
Store OldStore = St->getStore();
Store NewStore = StoreMgr->Remove(OldStore, LV);
@ -140,6 +95,13 @@ const GRState* GRStateManager::getPersistentState(GRState& State) {
return I;
}
const GRState* GRStateManager::MakeStateWithStore(const GRState* St,
Store store) {
GRState NewSt = *St;
NewSt.St = store;
return getPersistentState(NewSt);
}
//===----------------------------------------------------------------------===//
// State pretty-printing.

View File

@ -215,6 +215,20 @@ MemSpaceRegion* MemRegionManager::getUnknownRegion() {
return LazyAllocate(unknown);
}
bool MemRegionManager::onStack(const MemRegion* R) {
while (const SubRegion* SR = dyn_cast<SubRegion>(R))
R = SR->getSuperRegion();
return (R != 0) && (R == stack);
}
bool MemRegionManager::onHeap(const MemRegion* R) {
while (const SubRegion* SR = dyn_cast<SubRegion>(R))
R = SR->getSuperRegion();
return (R != 0) && (R == heap);
}
StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str) {
llvm::FoldingSetNodeID ID;
MemSpaceRegion* GlobalsR = getGlobalsRegion();

View File

@ -62,6 +62,16 @@ namespace clang {
};
}
// Regions that have default value zero.
// FIXME: redefinition!
// typedef llvm::ImmutableMap<const MemRegion*, SVal> RegionDefaultValue;
// static int RegionDefaultValueIndex = 0;
// namespace clang {
// template<> struct GRStateTrait<RegionDefaultValue>
// : public GRStatePartialTrait<RegionDefaultValue> {
// static void* GDMIndex() { return &RegionDefaultValueIndex; }
// };
// }
namespace {
@ -83,7 +93,8 @@ public:
MemRegionManager& getRegionManager() { return MRMgr; }
Store BindCompoundLiteral(Store store, const CompoundLiteralExpr* CL, SVal V);
const GRState* BindCompoundLiteral(const GRState* St,
const CompoundLiteralExpr* CL, SVal V);
SVal getLValueString(const GRState* St, const StringLiteral* S);
@ -107,13 +118,24 @@ public:
CastResult CastRegion(const GRState* state, const MemRegion* R,
QualType CastToTy);
/// The high level logic for this method is this:
/// Retrieve (L)
/// if L has binding
/// return L's binding
/// else if L is in killset
/// return unknown
/// else
/// if L is on stack or heap
/// return undefined
/// else
/// return symbolic
SVal Retrieve(const GRState* state, Loc L, QualType T = QualType());
Store Bind(Store St, Loc LV, SVal V);
const GRState* Bind(const GRState* St, Loc LV, SVal V);
Store Remove(Store store, Loc LV);
Store getInitialStore();
Store getInitialStore() { return RBFactory.GetEmptyMap().getRoot(); }
/// getSelfRegion - Returns the region for the 'self' (Objective-C) or
/// 'this' object (C++). When used when analyzing a normal function this
@ -133,7 +155,11 @@ public:
void UpdateLiveSymbols(SVal X, LiveSymbolsTy& LSymbols);
Store BindDecl(Store store, const VarDecl* VD, SVal* InitVal, unsigned Count);
const GRState* BindDecl(const GRState* St, const VarDecl* VD, SVal InitVal);
const GRState* BindDeclWithNoInit(const GRState* St, const VarDecl* VD) {
return St;
}
const GRState* setExtent(const GRState* St, const MemRegion* R, SVal Extent);
@ -152,22 +178,16 @@ private:
return loc::MemRegionVal(MRMgr.getVarRegion(VD));
}
Store InitializeArray(Store store, const TypedRegion* R, SVal Init);
Store BindArrayToVal(Store store, const TypedRegion* BaseR, SVal V);
Store BindArrayToSymVal(Store store, const TypedRegion* BaseR);
Store InitializeStruct(Store store, const TypedRegion* R, SVal Init);
Store BindStructToVal(Store store, const TypedRegion* BaseR, SVal V);
Store BindStructToSymVal(Store store, const TypedRegion* BaseR);
const GRState* BindArray(const GRState* St, const TypedRegion* R, SVal V);
/// Retrieve the values in a struct and return a CompoundVal, used when doing
/// struct copy:
/// struct s x, y;
/// x = y;
/// y's value is retrieved by this method.
SVal RetrieveStruct(Store store, const TypedRegion* R);
SVal RetrieveStruct(const GRState* St, const TypedRegion* R);
Store BindStruct(Store store, const TypedRegion* R, SVal V);
const GRState* BindStruct(const GRState* St, const TypedRegion* R, SVal V);
// Utility methods.
BasicValueFactory& getBasicVals() { return StateMgr.getBasicVals(); }
@ -396,41 +416,60 @@ RegionStoreManager::CastRegion(const GRState* state, const MemRegion* R,
return CastResult(AddRegionView(state, ViewR, R), ViewR);
}
SVal RegionStoreManager::Retrieve(const GRState* state, Loc L, QualType T) {
SVal RegionStoreManager::Retrieve(const GRState* St, Loc L, QualType T) {
assert(!isa<UnknownVal>(L) && "location unknown");
assert(!isa<UndefinedVal>(L) && "location undefined");
Store S = state->getStore();
switch (L.getSubKind()) {
case loc::MemRegionKind: {
if (isa<loc::SymbolVal>(L))
return UnknownVal();
if (isa<loc::ConcreteInt>(L))
return UndefinedVal();
if (isa<loc::FuncVal>(L))
return L;
const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion();
assert(R && "bad region");
if (const TypedRegion* TR = dyn_cast<TypedRegion>(R))
if (TR->getRValueType(getContext())->isStructureType())
return RetrieveStruct(S, TR);
return RetrieveStruct(St, TR);
RegionBindingsTy B(static_cast<const RegionBindingsTy::TreeTy*>(S));
RegionBindingsTy B = GetRegionBindings(St->getStore());
RegionBindingsTy::data_type* V = B.lookup(R);
return V ? *V : UnknownVal();
}
case loc::SymbolValKind:
// Check if the region has a binding.
if (V)
return *V;
// Check if the region is in killset.
GRStateRef state(St, StateMgr);
if (state.contains<RegionKills>(R))
return UnknownVal();
case loc::ConcreteIntKind:
return UndefinedVal(); // As in BasicStoreManager.
// The location is not initialized.
case loc::FuncValKind:
return L;
// We treat parameters as symbolic values.
if (const VarRegion* VR = dyn_cast<VarRegion>(R))
if (isa<ParmVarDecl>(VR->getDecl()))
return SVal::MakeSymbolValue(getSymbolManager(), VR,
VR->getRValueType(getContext()));
default:
assert(false && "Invalid Location");
return L;
}
if (MRMgr.onStack(R) || MRMgr.onHeap(R))
return UndefinedVal();
else
return SVal::MakeSymbolValue(getSymbolManager(), R,
cast<TypedRegion>(R)->getRValueType(getContext()));
// FIXME: consider default values for elements and fields.
}
SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) {
SVal RegionStoreManager::RetrieveStruct(const GRState* St,const TypedRegion* R){
Store store = St->getStore();
GRStateRef state(St, StateMgr);
// FIXME: Verify we want getRValueType instead of getLValueType.
QualType T = R->getRValueType(getContext());
assert(T->isStructureType());
@ -447,10 +486,21 @@ SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) {
FieldEnd = Fields.rend();
Field != FieldEnd; ++Field) {
FieldRegion* FR = MRMgr.getFieldRegion(*Field, R);
RegionBindingsTy B(static_cast<const RegionBindingsTy::TreeTy*>(store));
RegionBindingsTy B = GetRegionBindings(store);
RegionBindingsTy::data_type* data = B.lookup(FR);
SVal FieldValue = data ? *data : UnknownVal();
SVal FieldValue;
if (data)
FieldValue = *data;
else if (state.contains<RegionKills>(FR))
FieldValue = UnknownVal();
else {
if (MRMgr.onStack(FR) || MRMgr.onHeap(FR))
FieldValue = UndefinedVal();
else
FieldValue = SVal::MakeSymbolValue(getSymbolManager(), FR,
FR->getRValueType(getContext()));
}
StructVal = getBasicVals().consVals(FieldValue, StructVal);
}
@ -458,25 +508,37 @@ SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) {
return NonLoc::MakeCompoundVal(T, StructVal, getBasicVals());
}
Store RegionStoreManager::Bind(Store store, Loc LV, SVal V) {
if (LV.getSubKind() == loc::SymbolValKind)
return store;
assert(LV.getSubKind() == loc::MemRegionKind);
const MemRegion* R = cast<loc::MemRegionVal>(LV).getRegion();
const GRState* RegionStoreManager::Bind(const GRState* St, Loc L, SVal V) {
// Currently we don't bind value to symbolic location. But if the logic is
// made clear, we might change this decision.
if (isa<loc::SymbolVal>(L))
return St;
// If we get here, the location should be a region.
const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion();
assert(R);
// Check if the region is a struct region.
if (const TypedRegion* TR = dyn_cast<TypedRegion>(R))
// FIXME: Verify we want getRValueType().
if (TR->getRValueType(getContext())->isStructureType())
return BindStruct(store, TR, V);
return BindStruct(St, TR, V);
Store store = St->getStore();
RegionBindingsTy B = GetRegionBindings(store);
return V.isUnknown()
? RBFactory.Remove(B, R).getRoot()
: RBFactory.Add(B, R, V).getRoot();
if (V.isUnknown()) {
// Remove the binding.
store = RBFactory.Remove(B, R).getRoot();
// Add the region to the killset.
GRStateRef state(St, StateMgr);
St = state.add<RegionKills>(R);
}
else
store = RBFactory.Add(B, R, V).getRoot();
return StateMgr.MakeStateWithStore(St, store);
}
Store RegionStoreManager::Remove(Store store, Loc L) {
@ -488,150 +550,37 @@ Store RegionStoreManager::Remove(Store store, Loc L) {
return RBFactory.Remove(B, R).getRoot();
}
Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R, SVal V){
// Verify we want getRValueType.
QualType T = R->getRValueType(getContext());
assert(T->isStructureType());
const RecordType* RT = cast<RecordType>(T.getTypePtr());
RecordDecl* RD = RT->getDecl();
if (!RD->isDefinition()) {
// This can only occur when a pointer of incomplete struct type is used as a
// function argument.
assert(V.isUnknown());
return store;
}
RegionBindingsTy B = GetRegionBindings(store);
if (isa<UnknownVal>(V))
return BindStructToVal(store, R, UnknownVal());
nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(V);
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
RecordDecl::field_iterator FI = RD->field_begin(), FE = RD->field_end();
for (; FI != FE; ++FI, ++VI) {
assert(VI != VE);
FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
B = RBFactory.Add(B, FR, *VI);
}
return B.getRoot();
}
Store RegionStoreManager::getInitialStore() {
typedef LiveVariables::AnalysisDataTy LVDataTy;
LVDataTy& D = StateMgr.getLiveVariables().getAnalysisData();
Store St = RBFactory.GetEmptyMap().getRoot();
for (LVDataTy::decl_iterator I=D.begin_decl(), E=D.end_decl(); I != E; ++I) {
NamedDecl* ND = const_cast<NamedDecl*>(I->first);
if (VarDecl* VD = dyn_cast<VarDecl>(ND)) {
// Punt on static variables for now.
if (VD->getStorageClass() == VarDecl::Static)
continue;
VarRegion* VR = MRMgr.getVarRegion(VD);
QualType T = VD->getType();
// Only handle pointers and integers for now.
if (Loc::IsLocType(T) || T->isIntegerType()) {
// Initialize globals and parameters to symbolic values.
// Initialize local variables to undefined.
SVal X = (VD->hasGlobalStorage() || isa<ParmVarDecl>(VD) ||
isa<ImplicitParamDecl>(VD))
? SVal::GetSymbolValue(getSymbolManager(), VD)
: UndefinedVal();
St = Bind(St, getVarLoc(VD), X);
}
else if (T->isArrayType()) {
if (VD->hasGlobalStorage()) // Params cannot have array type.
St = BindArrayToSymVal(St, VR);
else
St = BindArrayToVal(St, VR, UndefinedVal());
}
else if (T->isStructureType()) {
if (VD->hasGlobalStorage() || isa<ParmVarDecl>(VD) ||
isa<ImplicitParamDecl>(VD))
St = BindStructToSymVal(St, VR);
else
St = BindStructToVal(St, VR, UndefinedVal());
}
}
}
const GRState* RegionStoreManager::BindDecl(const GRState* St,
const VarDecl* VD, SVal InitVal) {
// All static variables are treated as symbolic values.
if (VD->hasGlobalStorage())
return St;
}
Store RegionStoreManager::BindDecl(Store store, const VarDecl* VD,
SVal* InitVal, unsigned Count) {
if (VD->hasGlobalStorage()) {
// Static global variables should not be visited here.
assert(!(VD->getStorageClass() == VarDecl::Static &&
VD->isFileVarDecl()));
// Process static variables.
if (VD->getStorageClass() == VarDecl::Static) {
if (!InitVal) {
// Only handle pointer and integer static variables.
QualType T = VD->getType();
if (Loc::IsLocType(T))
store = Bind(store, getVarLoc(VD),
loc::ConcreteInt(getBasicVals().getValue(0, T)));
else if (T->isIntegerType())
store = Bind(store, getVarLoc(VD),
loc::ConcreteInt(getBasicVals().getValue(0, T)));
// Other types of static local variables are not handled yet.
} else {
store = Bind(store, getVarLoc(VD), *InitVal);
}
}
} else {
// Process local variables.
QualType T = VD->getType();
VarRegion* VR = MRMgr.getVarRegion(VD);
if (Loc::IsLocType(T) || T->isIntegerType()) {
SVal V = InitVal ? *InitVal : UndefinedVal();
store = Bind(store, loc::MemRegionVal(VR), V);
}
else if (T->isArrayType()) {
if (!InitVal)
store = BindArrayToVal(store, VR, UndefinedVal());
else
store = InitializeArray(store, VR, *InitVal);
}
else if (T->isStructureType()) {
if (!InitVal)
store = BindStructToVal(store, VR, UndefinedVal());
else
store = InitializeStruct(store, VR, *InitVal);
if (Loc::IsLocType(T) || T->isIntegerType())
return Bind(St, Loc::MakeVal(VR), InitVal);
else if (T->isArrayType())
return BindArray(St, VR, InitVal);
else if (T->isStructureType())
return BindStruct(St, VR, InitVal);
// Other types of variable are not supported yet.
return St;
}
// Other types of local variables are not handled yet.
}
return store;
}
Store RegionStoreManager::BindCompoundLiteral(Store store,
const CompoundLiteralExpr* CL,
SVal V) {
// FIXME: this method should be merged into Bind().
const GRState*
RegionStoreManager::BindCompoundLiteral(const GRState* St,
const CompoundLiteralExpr* CL, SVal V) {
CompoundLiteralRegion* R = MRMgr.getCompoundLiteralRegion(CL);
store = Bind(store, loc::MemRegionVal(R), V);
return store;
return Bind(St, loc::MemRegionVal(R), V);
}
const GRState* RegionStoreManager::setExtent(const GRState* St,
@ -781,19 +730,24 @@ void RegionStoreManager::print(Store store, std::ostream& Out,
}
}
Store RegionStoreManager::InitializeArray(Store store, const TypedRegion* R,
SVal Init) {
const GRState* RegionStoreManager::BindArray(const GRState* St,
const TypedRegion* R, SVal Init) {
// FIXME: Verify we should use getLValueType or getRValueType.
QualType T = R->getRValueType(getContext());
assert(T->isArrayType());
// When we are binding the whole array, it always has default value 0.
GRStateRef state(St, StateMgr);
// St = state.set<RegionDefaultValue>(R, NonLoc::MakeVal(getBasicVals(), 0,
// false));
Store store = St->getStore();
ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr());
llvm::APSInt Size(CAT->getSize(), false);
llvm::APSInt i = getBasicVals().getValue(0, Size.getBitWidth(),
Size.isUnsigned());
llvm::APSInt i = getBasicVals().getZeroWithPtrWidth(false);
// Check if the init expr is a StringLiteral.
if (isa<loc::MemRegionVal>(Init)) {
@ -803,21 +757,21 @@ Store RegionStoreManager::InitializeArray(Store store, const TypedRegion* R,
unsigned len = S->getByteLength();
unsigned j = 0;
// Copy bytes from the string literal into the target array. Trailing bytes
// in the array that are not covered by the string literal are initialized
// to zero.
for (; i < Size; ++i, ++j) {
if (j >= len)
break;
SVal Idx = NonLoc::MakeVal(getBasicVals(), i);
ElementRegion* ER = MRMgr.getElementRegion(Idx, R);
// Copy bytes from the string literal into the target array. Trailing
// bytes in the array that are not covered by the string literal are
// initialized to zero.
SVal V = (j < len)
? NonLoc::MakeVal(getBasicVals(), str[j], sizeof(char)*8, true)
: NonLoc::MakeVal(getBasicVals(), 0, sizeof(char)*8, true);
store = Bind(store, loc::MemRegionVal(ER), V);
SVal V = NonLoc::MakeVal(getBasicVals(), str[j], sizeof(char)*8, true);
St = Bind(St, loc::MemRegionVal(ER), V);
}
return store;
return StateMgr.MakeStateWithStore(St, store);
}
@ -825,79 +779,25 @@ Store RegionStoreManager::InitializeArray(Store store, const TypedRegion* R,
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
for (; i < Size; ++i) {
for (; i < Size; ++i, ++VI) {
// The init list might be shorter than the array decl.
if (VI == VE)
break;
SVal Idx = NonLoc::MakeVal(getBasicVals(), i);
ElementRegion* ER = MRMgr.getElementRegion(Idx, R);
store = Bind(store, loc::MemRegionVal(ER), (VI!=VE) ? *VI : UndefinedVal());
// The init list might be shorter than the array decl.
if (VI != VE) ++VI;
}
return store;
}
// Bind all elements of the array to some value.
Store RegionStoreManager::BindArrayToVal(Store store, const TypedRegion* BaseR,
SVal V){
// FIXME: Verify we want getRValueType.
QualType T = BaseR->getRValueType(getContext());
assert(T->isArrayType());
// Only handle constant size array for now.
if (ConstantArrayType* CAT=dyn_cast<ConstantArrayType>(T.getTypePtr())) {
llvm::APInt Size = CAT->getSize();
llvm::APInt i = llvm::APInt::getNullValue(Size.getBitWidth());
for (; i != Size; ++i) {
nonloc::ConcreteInt Idx(getBasicVals().getValue(llvm::APSInt(i, false)));
ElementRegion* ER = MRMgr.getElementRegion(Idx, BaseR);
if (CAT->getElementType()->isStructureType())
store = BindStructToVal(store, ER, V);
St = BindStruct(St, ER, *VI);
else
store = Bind(store, loc::MemRegionVal(ER), V);
}
St = Bind(St, Loc::MakeVal(ER), *VI);
}
return store;
return StateMgr.MakeStateWithStore(St, store);
}
Store RegionStoreManager::BindArrayToSymVal(Store store,
const TypedRegion* BaseR) {
// FIXME: Verify we want getRValueType.
QualType T = BaseR->getRValueType(getContext());
assert(T->isArrayType());
if (ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(T.getTypePtr())) {
llvm::APInt Size = CAT->getSize();
llvm::APInt i = llvm::APInt::getNullValue(Size.getBitWidth());
for (; i != Size; ++i) {
nonloc::ConcreteInt Idx(getBasicVals().getValue(llvm::APSInt(i, false)));
ElementRegion* ER = MRMgr.getElementRegion(Idx, BaseR);
if (CAT->getElementType()->isStructureType()) {
store = BindStructToSymVal(store, ER);
}
else {
SVal V = SVal::getSymbolValue(getSymbolManager(), BaseR,
&Idx.getValue(), CAT->getElementType());
store = Bind(store, loc::MemRegionVal(ER), V);
}
}
}
return store;
}
Store RegionStoreManager::InitializeStruct(Store store, const TypedRegion* R,
SVal Init) {
const GRState*
RegionStoreManager::BindStruct(const GRState* St, const TypedRegion* R, SVal V){
// FIXME: Verify that we should use getRValueType or getLValueType.
QualType T = R->getRValueType(getContext());
assert(T->isStructureType());
@ -906,102 +806,35 @@ Store RegionStoreManager::InitializeStruct(Store store, const TypedRegion* R,
RecordDecl* RD = RT->getDecl();
assert(RD->isDefinition());
nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(Init);
nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(V);
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
RecordDecl::field_iterator FI = RD->field_begin(), FE = RD->field_end();
for (; FI != FE; ++FI) {
for (; FI != FE; ++FI, ++VI) {
// There may be fewer values than fields only when we are initializing a
// struct decl. In this case, mark the region as having default value.
if (VI == VE) {
// GRStateRef state(St, StateMgr);
//St = state.set<RegionDefaultValue>(R, NonLoc::MakeVal(getBasicVals(), 0,
// false));
break;
}
QualType FTy = (*FI)->getType();
FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
if (Loc::IsLocType(FTy) || FTy->isIntegerType()) {
if (VI != VE) {
store = Bind(store, loc::MemRegionVal(FR), *VI);
++VI;
} else
store = Bind(store, loc::MemRegionVal(FR), UndefinedVal());
}
else if (FTy->isArrayType()) {
if (VI != VE) {
store = InitializeArray(store, FR, *VI);
++VI;
} else
store = BindArrayToVal(store, FR, UndefinedVal());
}
else if (FTy->isStructureType()) {
if (VI != VE) {
store = InitializeStruct(store, FR, *VI);
++VI;
} else
store = BindStructToVal(store, FR, UndefinedVal());
}
}
return store;
if (Loc::IsLocType(FTy) || FTy->isIntegerType())
St = Bind(St, Loc::MakeVal(FR), *VI);
else if (FTy->isArrayType())
St = BindArray(St, FR, *VI);
else if (FTy->isStructureType())
St = BindStruct(St, FR, *VI);
}
// Bind all fields of the struct to some value.
Store RegionStoreManager::BindStructToVal(Store store, const TypedRegion* BaseR,
SVal V) {
// FIXME: Verify that we should use getLValueType or getRValueType.
QualType T = BaseR->getRValueType(getContext());
assert(T->isStructureType());
const RecordType* RT = cast<RecordType>(T.getTypePtr());
RecordDecl* RD = RT->getDecl();
assert(RD->isDefinition());
RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
for (; I != E; ++I) {
QualType FTy = (*I)->getType();
FieldRegion* FR = MRMgr.getFieldRegion(*I, BaseR);
if (Loc::IsLocType(FTy) || FTy->isIntegerType()) {
store = Bind(store, loc::MemRegionVal(FR), V);
} else if (FTy->isArrayType()) {
store = BindArrayToVal(store, FR, V);
} else if (FTy->isStructureType()) {
store = BindStructToVal(store, FR, V);
}
}
return store;
}
Store RegionStoreManager::BindStructToSymVal(Store store,
const TypedRegion* BaseR) {
// FIXME: Verify that we should use getLValueType or getRValueType
QualType T = BaseR->getRValueType(getContext());
assert(T->isStructureType());
const RecordType* RT = cast<RecordType>(T.getTypePtr());
RecordDecl* RD = RT->getDecl();
assert(RD->isDefinition());
RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
for (; I != E; ++I) {
QualType FTy = (*I)->getType();
FieldRegion* FR = MRMgr.getFieldRegion(*I, BaseR);
if (Loc::IsLocType(FTy) || FTy->isIntegerType()) {
store = Bind(store, loc::MemRegionVal(FR),
SVal::getSymbolValue(getSymbolManager(), BaseR, *I, FTy));
}
else if (FTy->isArrayType()) {
store = BindArrayToSymVal(store, FR);
}
else if (FTy->isStructureType()) {
store = BindStructToSymVal(store, FR);
}
}
return store;
return St;
}
const GRState* RegionStoreManager::AddRegionView(const GRState* St,

View File

@ -242,6 +242,11 @@ NonLoc Loc::NE(BasicValueFactory& BasicVals, const Loc& R) const {
//===----------------------------------------------------------------------===//
// Utility methods for constructing Non-Locs.
//===----------------------------------------------------------------------===//
NonLoc NonLoc::MakeVal(SymbolRef sym) {
return nonloc::SymbolVal(sym);
}
NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, unsigned X,
bool isUnsigned) {
return nonloc::ConcreteInt(BasicVals.getValue(X, sizeof(unsigned)*8,
@ -281,6 +286,14 @@ NonLoc NonLoc::MakeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals,
return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals));
}
SVal SVal::MakeSymbolValue(SymbolManager& SymMgr, const MemRegion* R,
QualType T) {
if (Loc::IsLocType(T))
return Loc::MakeVal(SymMgr.getSymbol(R));
else
return NonLoc::MakeVal(SymMgr.getSymbol(R));
}
SVal SVal::GetSymbolValue(SymbolManager& SymMgr, VarDecl* D) {
QualType T = D->getType();
@ -320,6 +333,8 @@ Loc Loc::MakeVal(const MemRegion* R) { return loc::MemRegionVal(R); }
Loc Loc::MakeVal(AddrLabelExpr* E) { return loc::GotoLabel(E->getLabel()); }
Loc Loc::MakeVal(SymbolRef sym) { return loc::SymbolVal(sym); }
//===----------------------------------------------------------------------===//
// Pretty-Printing.
//===----------------------------------------------------------------------===//

View File

@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/SymbolManager.h"
#include "clang/Analysis/PathSensitive/MemRegion.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@ -21,14 +22,35 @@ void SymbolRef::print(llvm::raw_ostream& os) const {
os << getNumber();
}
SymbolRef SymbolManager::getSymbol(VarDecl* D) {
SymbolRef SymbolManager::getSymbol(const MemRegion* R) {
switch (R->getKind()) {
case MemRegion::VarRegionKind:
return getSymbol(cast<VarRegion>(R)->getDecl());
case MemRegion::ElementRegionKind: {
const ElementRegion* ER = cast<ElementRegion>(R);
const llvm::APSInt& Idx =
cast<nonloc::ConcreteInt>(ER->getIndex()).getValue();
return getElementSymbol(ER->getSuperRegion(), &Idx);
}
case MemRegion::FieldRegionKind: {
const FieldRegion* FR = cast<FieldRegion>(R);
return getFieldSymbol(FR->getSuperRegion(), FR->getDecl());
}
default:
assert(0 && "unprocessed region");
}
}
SymbolRef SymbolManager::getSymbol(const VarDecl* D) {
assert (isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) ||
D->hasGlobalStorage());
llvm::FoldingSetNodeID profile;
ParmVarDecl* PD = dyn_cast<ParmVarDecl>(D);
const ParmVarDecl* PD = dyn_cast<ParmVarDecl>(D);
if (PD)
SymbolDataParmVar::Profile(profile, PD);

View File

@ -1,5 +1,5 @@
// RUN: clang -std=gnu99 -checker-simple -verify %s &&
// RUN: clang -std=gnu99 -checker-simple -analyzer-store-region -verify %s
// RUN: clang -std=gnu99 -checker-simple -verify %s
// DISABLE: clang -std=gnu99 -checker-simple -analyzer-store-region -verify %s
#include<stdint.h>
#include <assert.h>

View File

@ -1,4 +1,4 @@
// RUN: clang -checker-simple -analyzer-store-region -verify %s
// DISABLE: clang -checker-simple -analyzer-store-region -verify %s
struct s {
int data;