Newer
Older
//== BasicStore.cpp - Basic map from Locations to Values --------*- C++ -*--==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defined the BasicStore and BasicStoreManager classes.
//
//===----------------------------------------------------------------------===//
Ted Kremenek
committed
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/Support/Compiler.h"
Ted Kremenek
committed
#include "llvm/Support/Streams.h"
using namespace clang;
Zhongxing Xu
committed
typedef llvm::ImmutableMap<const VarDecl*,SVal> VarBindingsTy;
namespace {
class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager {
VarBindingsTy::Factory VBFactory;
GRStateManager& StateMgr;
const MemRegion* SelfRegion;
public:
BasicStoreManager(GRStateManager& mgr)
Ted Kremenek
committed
: StoreManager(mgr.getAllocator()),
VBFactory(mgr.getAllocator()),
Zhongxing Xu
committed
StateMgr(mgr),
SelfRegion(0) {}
~BasicStoreManager() {}
Ted Kremenek
committed
SVal Retrieve(const GRState *state, Loc loc, QualType T = QualType());
const GRState* Bind(const GRState* St, Loc L, SVal V) {
Store store = St->getStore();
store = BindInternal(store, L, V);
return StateMgr.MakeStateWithStore(St, store);
}
Ted Kremenek
committed
Store BindInternal(Store St, Loc loc, SVal V);
Store Remove(Store St, Loc loc);
Store getInitialStore();
Zhongxing Xu
committed
// FIXME: Investigate what is using this. This method should be removed.
Zhongxing Xu
committed
virtual Loc getLoc(const VarDecl* VD) {
return Loc::MakeVal(MRMgr.getVarRegion(VD));
Ted Kremenek
committed
const GRState* BindCompoundLiteral(const GRState* St,
const CompoundLiteralExpr* CL,
SVal V) {
return St;
}
Zhongxing Xu
committed
SVal getLValueVar(const GRState* St, const VarDecl* VD);
Zhongxing Xu
committed
SVal getLValueString(const GRState* St, const StringLiteral* S);
Zhongxing Xu
committed
SVal getLValueCompoundLiteral(const GRState* St,
const CompoundLiteralExpr* CL);
Zhongxing Xu
committed
SVal getLValueIvar(const GRState* St, const ObjCIvarDecl* D, SVal Base);
SVal getLValueField(const GRState* St, SVal Base, const FieldDecl* D);
Zhongxing Xu
committed
SVal getLValueElement(const GRState* St, SVal Base, SVal Offset);
Zhongxing Xu
committed
/// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit
/// conversions between arrays and pointers.
Zhongxing Xu
committed
SVal ArrayToPointer(SVal Array) { return Array; }
/// CastRegion - Used by GRExprEngine::VisitCast to handle casts from
/// a MemRegion* to a specific location type. 'R' is the region being
/// casted and 'CastToTy' the result type of the cast.
CastResult CastRegion(const GRState* state, const MemRegion* R,
QualType CastToTy);
/// getSelfRegion - Returns the region for the 'self' (Objective-C) or
/// 'this' object (C++). When used when analyzing a normal function this
/// method returns NULL.
const MemRegion* getSelfRegion(Store) {
return SelfRegion;
}
/// RemoveDeadBindings - Scans a BasicStore of 'state' for dead values.
/// It returns a new Store with these values removed, and populates LSymbols
/// and DSymbols with the known set of live and dead symbols respectively.
Ted Kremenek
committed
Store
RemoveDeadBindings(const GRState* state, Stmt* Loc,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
void iterBindings(Store store, BindingsHandler& f);
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);
}
Store BindDeclInternal(Store store, const VarDecl* VD, SVal* InitVal);
static inline VarBindingsTy GetVarBindings(Store store) {
return VarBindingsTy(static_cast<const VarBindingsTy::TreeTy*>(store));
Ted Kremenek
committed
}
void print(Store store, std::ostream& Out, const char* nl, const char *sep);
Ted Kremenek
committed
} // end anonymous namespace
Ted Kremenek
committed
StoreManager* clang::CreateBasicStoreManager(GRStateManager& StMgr) {
return new BasicStoreManager(StMgr);
Zhongxing Xu
committed
SVal BasicStoreManager::getLValueVar(const GRState* St, const VarDecl* VD) {
return Loc::MakeVal(MRMgr.getVarRegion(VD));
Ted Kremenek
committed
}
Zhongxing Xu
committed
SVal BasicStoreManager::getLValueString(const GRState* St,
const StringLiteral* S) {
return Loc::MakeVal(MRMgr.getStringRegion(S));
Zhongxing Xu
committed
}
Zhongxing Xu
committed
SVal BasicStoreManager::getLValueCompoundLiteral(const GRState* St,
const CompoundLiteralExpr* CL){
return Loc::MakeVal(MRMgr.getCompoundLiteralRegion(CL));
Zhongxing Xu
committed
}
Zhongxing Xu
committed
SVal BasicStoreManager::getLValueIvar(const GRState* St, const ObjCIvarDecl* D,
SVal Base) {
Ted Kremenek
committed
return UnknownVal();
}
/// CastRegion - Used by GRExprEngine::VisitCast to handle casts from
/// a MemRegion* to a specific location type. 'R' is the region being
/// casted and 'CastToTy' the result type of the cast.
StoreManager::CastResult
BasicStoreManager::CastRegion(const GRState* state, const MemRegion* R,
QualType CastToTy) {
// Return the same region if the region types are compatible.
if (const TypedRegion* TR = dyn_cast<TypedRegion>(R)) {
ASTContext& Ctx = StateMgr.getContext();
QualType Ta = Ctx.getCanonicalType(TR->getLValueType(Ctx));
QualType Tb = Ctx.getCanonicalType(CastToTy);
if (Ta == Tb)
return CastResult(state, R);
}
return CastResult(state, MRMgr.getAnonTypedRegion(CastToTy, R));
}
Ted Kremenek
committed
SVal BasicStoreManager::getLValueField(const GRState* St, SVal Base,
const FieldDecl* D) {
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
if (Base.isUnknownOrUndef())
return Base;
Loc BaseL = cast<Loc>(Base);
const MemRegion* BaseR = 0;
switch(BaseL.getSubKind()) {
case loc::SymbolValKind:
BaseR = MRMgr.getSymbolicRegion(cast<loc::SymbolVal>(&BaseL)->getSymbol());
break;
case loc::GotoLabelKind:
case loc::FuncValKind:
// Technically we can get here if people do funny things with casts.
return UndefinedVal();
case loc::MemRegionKind:
BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
break;
case loc::ConcreteIntKind:
// While these seem funny, this can happen through casts.
// FIXME: What we should return is the field offset. For example,
// add the field offset to the integer value. That way funny things
// like this work properly: &(((struct foo *) 0xa)->f)
return Base;
default:
assert ("Unhandled Base.");
return Base;
}
return Loc::MakeVal(MRMgr.getFieldRegion(D, BaseR));
Ted Kremenek
committed
}
Zhongxing Xu
committed
SVal BasicStoreManager::getLValueElement(const GRState* St, SVal Base,
SVal Offset) {
if (Base.isUnknownOrUndef())
return Base;
Loc BaseL = cast<Loc>(Base);
const TypedRegion* BaseR = 0;
switch(BaseL.getSubKind()) {
Ted Kremenek
committed
case loc::SymbolValKind: {
// FIXME: Should we have symbolic regions be typed or typeless?
// Here we assume that these regions are typeless, even though the
// symbol is typed.
SymbolRef Sym = cast<loc::SymbolVal>(&BaseL)->getSymbol();
// Create a region to represent this symbol.
// FIXME: In the future we may just use symbolic regions instead of
// SymbolVals to reason about symbolic memory chunks.
const MemRegion* SymR = MRMgr.getSymbolicRegion(Sym);
// Layered a typed region on top of this.
QualType T = StateMgr.getSymbolManager().getType(Sym);
BaseR = MRMgr.getAnonTypedRegion(T, SymR);
break;
Ted Kremenek
committed
}
case loc::GotoLabelKind:
case loc::FuncValKind:
// Technically we can get here if people do funny things with casts.
return UndefinedVal();
case loc::MemRegionKind: {
const MemRegion *R = cast<loc::MemRegionVal>(BaseL).getRegion();
if (isa<ElementRegion>(R)) {
// Basic example:
// char buf[100];
// char *q = &buf[1]; // p points to ElementRegion(buf,Unknown)
// &q[10]
assert(cast<ElementRegion>(R)->getIndex().isUnknown());
return Base;
}
if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
BaseR = TR;
break;
}
// FIXME: Handle SymbolRegions? Shouldn't be possible in
// BasicStoreManager.
assert(!isa<SymbolicRegion>(R));
break;
case loc::ConcreteIntKind:
// While these seem funny, this can happen through casts.
// FIXME: What we should return is the field offset. For example,
// add the field offset to the integer value. That way funny things
// like this work properly: &(((struct foo *) 0xa)->f)
return Base;
default:
assert ("Unhandled Base.");
return Base;
}
if (BaseR)
return Loc::MakeVal(MRMgr.getElementRegion(UnknownVal(), BaseR));
else
return UnknownVal();
Zhongxing Xu
committed
}
Ted Kremenek
committed
SVal BasicStoreManager::Retrieve(const GRState* state, Loc loc, QualType T) {
Ted Kremenek
committed
if (isa<UnknownVal>(loc))
return UnknownVal();
Ted Kremenek
committed
assert (!isa<UndefinedVal>(loc));
Ted Kremenek
committed
switch (loc.getSubKind()) {
Zhongxing Xu
committed
case loc::MemRegionKind: {
const VarRegion* R =
Ted Kremenek
committed
dyn_cast<VarRegion>(cast<loc::MemRegionVal>(loc).getRegion());
Ted Kremenek
committed
if (!R)
return UnknownVal();
Store store = state->getStore();
Ted Kremenek
committed
VarBindingsTy::data_type* T = B.lookup(R->getDecl());
return T ? *T : UnknownVal();
}
Zhongxing Xu
committed
case loc::SymbolValKind:
return UnknownVal();
Zhongxing Xu
committed
case loc::ConcreteIntKind:
// Some clients may call GetSVal with such an option simply because
// they are doing a quick scan through their Locs (potentially to
// invalidate their bindings). Just return Undefined.
Ted Kremenek
committed
return UndefinedVal();
Zhongxing Xu
committed
case loc::FuncValKind:
Ted Kremenek
committed
return loc;
default:
Zhongxing Xu
committed
assert (false && "Invalid Loc.");
break;
}
return UnknownVal();
}
Ted Kremenek
committed
Store BasicStoreManager::BindInternal(Store store, Loc loc, SVal V) {
switch (loc.getSubKind()) {
Zhongxing Xu
committed
case loc::MemRegionKind: {
const VarRegion* R =
Ted Kremenek
committed
dyn_cast<VarRegion>(cast<loc::MemRegionVal>(loc).getRegion());
Ted Kremenek
committed
if (!R)
return store;
VarBindingsTy B = GetVarBindings(store);
return V.isUnknown()
Ted Kremenek
committed
? VBFactory.Remove(B, R->getDecl()).getRoot()
: VBFactory.Add(B, R->getDecl(), V).getRoot();
}
default:
Zhongxing Xu
committed
assert ("SetSVal for given Loc type not yet implemented.");
return store;
}
}
Ted Kremenek
committed
Store BasicStoreManager::Remove(Store store, Loc loc) {
switch (loc.getSubKind()) {
Zhongxing Xu
committed
case loc::MemRegionKind: {
const VarRegion* R =
Ted Kremenek
committed
dyn_cast<VarRegion>(cast<loc::MemRegionVal>(loc).getRegion());
Ted Kremenek
committed
if (!R)
return store;
VarBindingsTy B = GetVarBindings(store);
Ted Kremenek
committed
return VBFactory.Remove(B,R->getDecl()).getRoot();
}
default:
Zhongxing Xu
committed
assert ("Remove for given Loc type not yet implemented.");
return store;
}
}
Ted Kremenek
committed
Store
BasicStoreManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
Ted Kremenek
committed
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
{
Store store = state->getStore();
VarBindingsTy B = GetVarBindings(store);
Zhongxing Xu
committed
typedef SVal::symbol_iterator symbol_iterator;
// Iterate over the variable bindings.
for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I)
Ted Kremenek
committed
if (SymReaper.isLive(Loc, I.getKey())) {
RegionRoots.push_back(MRMgr.getVarRegion(I.getKey()));
Zhongxing Xu
committed
SVal X = I.getData();
for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
Ted Kremenek
committed
SymReaper.markLive(*SI);
}
// Scan for live variables and live symbols.
Ted Kremenek
committed
llvm::SmallPtrSet<const VarRegion*, 10> Marked;
Ted Kremenek
committed
while (!RegionRoots.empty()) {
const MemRegion* MR = RegionRoots.back();
Ted Kremenek
committed
RegionRoots.pop_back();
while (MR) {
if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(MR)) {
Ted Kremenek
committed
SymReaper.markLive(SymR->getSymbol());
break;
}
else if (const VarRegion* R = dyn_cast<VarRegion>(MR)) {
if (Marked.count(R))
break;
Marked.insert(R);
Ted Kremenek
committed
SVal X = Retrieve(state, loc::MemRegionVal(R));
// FIXME: We need to handle symbols nested in region definitions.
Ted Kremenek
committed
for (symbol_iterator SI=X.symbol_begin(),SE=X.symbol_end();SI!=SE;++SI)
SymReaper.markLive(*SI);
if (!isa<loc::MemRegionVal>(X))
break;
const loc::MemRegionVal& LVD = cast<loc::MemRegionVal>(X);
RegionRoots.push_back(LVD.getRegion());
break;
}
else if (const SubRegion* R = dyn_cast<SubRegion>(MR))
MR = R->getSuperRegion();
else
break;
}
}
// Remove dead variable bindings.
Ted Kremenek
committed
for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) {
const VarRegion* R = cast<VarRegion>(MRMgr.getVarRegion(I.getKey()));
Ted Kremenek
committed
if (!Marked.count(R)) {
store = Remove(store, Loc::MakeVal(R));
Zhongxing Xu
committed
SVal X = I.getData();
for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
Ted Kremenek
committed
SymReaper.maybeDead(*SI);
}
Ted Kremenek
committed
}
return store;
}
Store BasicStoreManager::getInitialStore() {
// The LiveVariables information already has a compilation of all VarDecls
// used in the function. Iterate through this set, and "symbolicate"
// any VarDecl whose value originally comes from outside the function.
typedef LiveVariables::AnalysisDataTy LVDataTy;
LVDataTy& D = StateMgr.getLiveVariables().getAnalysisData();
Store St = VBFactory.GetEmptyMap().getRoot();
for (LVDataTy::decl_iterator I=D.begin_decl(), E=D.end_decl(); I != E; ++I) {
NamedDecl* ND = const_cast<NamedDecl*>(I->first);
// Handle implicit parameters.
if (ImplicitParamDecl* PD = dyn_cast<ImplicitParamDecl>(ND)) {
const Decl& CD = StateMgr.getCodeDecl();
if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CD)) {
if (MD->getSelfDecl() == PD) {
// Create a region for "self".
assert (SelfRegion == 0);
SelfRegion = MRMgr.getObjCObjectRegion(MD->getClassInterface(),
MRMgr.getHeapRegion());
St = BindInternal(St, Loc::MakeVal(MRMgr.getVarRegion(PD)),
Loc::MakeVal(SelfRegion));
}
}
}
else if (VarDecl* VD = dyn_cast<VarDecl>(ND)) {
// Punt on static variables for now.
if (VD->getStorageClass() == VarDecl::Static)
continue;
// Only handle pointers and integers for now.
QualType T = VD->getType();
Zhongxing Xu
committed
if (Loc::IsLocType(T) || T->isIntegerType()) {
// Initialize globals and parameters to symbolic values.
// Initialize local variables to undefined.
const MemRegion *R = StateMgr.getRegion(VD);
Zhongxing Xu
committed
SVal X = (VD->hasGlobalStorage() || isa<ParmVarDecl>(VD) ||
? SVal::GetRValueSymbolVal(StateMgr.getSymbolManager(), R)
: UndefinedVal();
St = BindInternal(St, Loc::MakeVal(R), X);
Ted Kremenek
committed
Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD,
SVal* InitVal) {
Ted Kremenek
committed
BasicValueFactory& BasicVals = StateMgr.getBasicVals();
Ted Kremenek
committed
// BasicStore does not model arrays and structs.
if (VD->getType()->isArrayType() || VD->getType()->isStructureType())
return store;
if (VD->hasGlobalStorage()) {
// Handle variables with global storage: extern, static, PrivateExtern.
// FIXME:: static variables may have an initializer, but the second time a
// function is called those values may not be current. Currently, a function
// will not be called more than once.
// Static global variables should not be visited here.
assert(!(VD->getStorageClass() == VarDecl::Static &&
VD->isFileVarDecl()));
// Process static variables.
if (VD->getStorageClass() == VarDecl::Static) {
// C99: 6.7.8 Initialization
// If an object that has static storage duration is not initialized
// explicitly, then:
// —if it has pointer type, it is initialized to a null pointer;
// —if it has arithmetic type, it is initialized to (positive or
// unsigned) zero;
Ted Kremenek
committed
if (!InitVal) {
QualType T = VD->getType();
Zhongxing Xu
committed
if (Loc::IsLocType(T))
store = BindInternal(store, getLoc(VD),
loc::ConcreteInt(BasicVals.getValue(0, T)));
else if (T->isIntegerType())
store = BindInternal(store, getLoc(VD),
nonloc::ConcreteInt(BasicVals.getValue(0, T)));
else {
// assert(0 && "ignore other types of variables");
}
} else {
store = BindInternal(store, getLoc(VD), *InitVal);
}
}
} else {
// Process local scalar variables.
QualType T = VD->getType();
Zhongxing Xu
committed
if (Loc::IsLocType(T) || T->isIntegerType()) {
Ted Kremenek
committed
SVal V = InitVal ? *InitVal : UndefinedVal();
store = BindInternal(store, getLoc(VD), V);
}
}
return store;
}
Ted Kremenek
committed
void BasicStoreManager::print(Store store, std::ostream& Out,
const char* nl, const char *sep) {
VarBindingsTy B = GetVarBindings(store);
Out << "Variables:" << nl;
bool isFirst = true;
for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {
if (isFirst) isFirst = false;
else Out << nl;
Out << ' ' << I.getKey()->getNameAsString() << " : ";
Ted Kremenek
committed
I.getData().print(Out);
}
}
Ted Kremenek
committed
void BasicStoreManager::iterBindings(Store store, BindingsHandler& f) {
VarBindingsTy B = GetVarBindings(store);
Ted Kremenek
committed
for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {
f.HandleBinding(*this, store, MRMgr.getVarRegion(I.getKey()),I.getData());
Ted Kremenek
committed
}
}
StoreManager::BindingsHandler::~BindingsHandler() {}