llvm-project/clang/lib/Analysis/BasicStore.cpp

578 lines
19 KiB
C++
Raw Normal View History

//== 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.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/PathSensitive/GRState.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Streams.h"
using namespace clang;
typedef llvm::ImmutableMap<const VarDecl*,SVal> VarBindingsTy;
namespace {
class VISIBILITY_HIDDEN BasicStoreSubRegionMap : public SubRegionMap {
public:
BasicStoreSubRegionMap() {}
void iterSubRegions(const MemRegion* R, Visitor& V) const {
// Do nothing. No subregions.
}
};
class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager {
VarBindingsTy::Factory VBFactory;
GRStateManager& StateMgr;
const MemRegion* SelfRegion;
public:
BasicStoreManager(GRStateManager& mgr)
: StoreManager(mgr.getAllocator()),
VBFactory(mgr.getAllocator()),
StateMgr(mgr),
SelfRegion(0) {}
~BasicStoreManager() {}
std::auto_ptr<SubRegionMap> getSubRegionMap(const GRState *state) {
return std::auto_ptr<SubRegionMap>(new BasicStoreSubRegionMap());
}
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);
}
Store BindInternal(Store St, Loc loc, SVal V);
Store Remove(Store St, Loc loc);
Store getInitialStore();
// FIXME: Investigate what is using this. This method should be removed.
virtual Loc getLoc(const VarDecl* VD) {
return Loc::MakeVal(MRMgr.getVarRegion(VD));
}
const GRState* BindCompoundLiteral(const GRState* St,
const CompoundLiteralExpr* CL,
SVal V) {
return St;
}
SVal getLValueVar(const GRState* St, const VarDecl* VD);
SVal getLValueString(const GRState* St, const StringLiteral* S);
SVal getLValueCompoundLiteral(const GRState* St,
const CompoundLiteralExpr* CL);
SVal getLValueIvar(const GRState* St, const ObjCIvarDecl* D, SVal Base);
SVal getLValueField(const GRState* St, SVal Base, const FieldDecl* D);
SVal getLValueElement(const GRState* St, SVal Base, SVal Offset);
/// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit
/// conversions between arrays and pointers.
SVal ArrayToPointer(SVal Array) { return Array; }
MemRegion: - Overhauled the notion of "types" for TypedRegions. We now distinguish between the "lvalue" of a region (via getLValueRegion()) and the "rvalue" of a region (va getRValueRegion()). Since a region represents a chunk of memory it has both, but we were conflating these concepts in some cases, leading to some insidious bugs. - Removed AnonPointeeType, partially because it is unused and because it doesn't have a clear notion of lvalue vs rvalue type. We can add it back once there is a need for it and we can resolve its role with these concepts. StoreManager: - Overhauled StoreManager::CastRegion. It expects an *lvalue* type for a region. This is actually what motivated the overhaul to the MemRegion type mechanism. It also no longer returns an SVal; we can just return a MemRegion*. - BasicStoreManager::CastRegion now overlays an "AnonTypedRegion" for pointer-pointer casts. This matches with the MemRegion changes. - Similar changes to RegionStore, except I've added a bunch of FIXMEs where it wasn't 100% clear where we should use TypedRegion::getRValueRegion() or TypedRegion::getLValueRegion(). AuditCFNumberCreate check: - Now blasts through AnonTypedRegions that may layer the original memory region, thus checking if the actually memory block is of the appropriate type. This change was needed to work with the changes to StoreManager::CastRegion. GRExprEngine::VisitCast: - Conform to the new interface of StoreManager::CastRegion. Tests: - None of the analysis tests fail now for using the "basic store". - Disabled the tests 'array-struct.c' and 'rdar-6442306-1.m' pending further testing and bug fixing. llvm-svn: 60995
2008-12-14 05:49:13 +08:00
/// 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.
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));
}
void print(Store store, std::ostream& Out, const char* nl, const char *sep);
};
} // end anonymous namespace
StoreManager* clang::CreateBasicStoreManager(GRStateManager& StMgr) {
return new BasicStoreManager(StMgr);
}
SVal BasicStoreManager::getLValueVar(const GRState* St, const VarDecl* VD) {
return Loc::MakeVal(MRMgr.getVarRegion(VD));
}
SVal BasicStoreManager::getLValueString(const GRState* St,
const StringLiteral* S) {
return Loc::MakeVal(MRMgr.getStringRegion(S));
}
SVal BasicStoreManager::getLValueCompoundLiteral(const GRState* St,
const CompoundLiteralExpr* CL){
return Loc::MakeVal(MRMgr.getCompoundLiteralRegion(CL));
}
SVal BasicStoreManager::getLValueIvar(const GRState* St, const ObjCIvarDecl* D,
SVal Base) {
return UnknownVal();
}
MemRegion: - Overhauled the notion of "types" for TypedRegions. We now distinguish between the "lvalue" of a region (via getLValueRegion()) and the "rvalue" of a region (va getRValueRegion()). Since a region represents a chunk of memory it has both, but we were conflating these concepts in some cases, leading to some insidious bugs. - Removed AnonPointeeType, partially because it is unused and because it doesn't have a clear notion of lvalue vs rvalue type. We can add it back once there is a need for it and we can resolve its role with these concepts. StoreManager: - Overhauled StoreManager::CastRegion. It expects an *lvalue* type for a region. This is actually what motivated the overhaul to the MemRegion type mechanism. It also no longer returns an SVal; we can just return a MemRegion*. - BasicStoreManager::CastRegion now overlays an "AnonTypedRegion" for pointer-pointer casts. This matches with the MemRegion changes. - Similar changes to RegionStore, except I've added a bunch of FIXMEs where it wasn't 100% clear where we should use TypedRegion::getRValueRegion() or TypedRegion::getLValueRegion(). AuditCFNumberCreate check: - Now blasts through AnonTypedRegions that may layer the original memory region, thus checking if the actually memory block is of the appropriate type. This change was needed to work with the changes to StoreManager::CastRegion. GRExprEngine::VisitCast: - Conform to the new interface of StoreManager::CastRegion. Tests: - None of the analysis tests fail now for using the "basic store". - Disabled the tests 'array-struct.c' and 'rdar-6442306-1.m' pending further testing and bug fixing. llvm-svn: 60995
2008-12-14 05:49:13 +08:00
/// 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.getTypedViewRegion(CastToTy, R));
MemRegion: - Overhauled the notion of "types" for TypedRegions. We now distinguish between the "lvalue" of a region (via getLValueRegion()) and the "rvalue" of a region (va getRValueRegion()). Since a region represents a chunk of memory it has both, but we were conflating these concepts in some cases, leading to some insidious bugs. - Removed AnonPointeeType, partially because it is unused and because it doesn't have a clear notion of lvalue vs rvalue type. We can add it back once there is a need for it and we can resolve its role with these concepts. StoreManager: - Overhauled StoreManager::CastRegion. It expects an *lvalue* type for a region. This is actually what motivated the overhaul to the MemRegion type mechanism. It also no longer returns an SVal; we can just return a MemRegion*. - BasicStoreManager::CastRegion now overlays an "AnonTypedRegion" for pointer-pointer casts. This matches with the MemRegion changes. - Similar changes to RegionStore, except I've added a bunch of FIXMEs where it wasn't 100% clear where we should use TypedRegion::getRValueRegion() or TypedRegion::getLValueRegion(). AuditCFNumberCreate check: - Now blasts through AnonTypedRegions that may layer the original memory region, thus checking if the actually memory block is of the appropriate type. This change was needed to work with the changes to StoreManager::CastRegion. GRExprEngine::VisitCast: - Conform to the new interface of StoreManager::CastRegion. Tests: - None of the analysis tests fail now for using the "basic store". - Disabled the tests 'array-struct.c' and 'rdar-6442306-1.m' pending further testing and bug fixing. llvm-svn: 60995
2008-12-14 05:49:13 +08:00
}
SVal BasicStoreManager::getLValueField(const GRState* St, SVal Base,
const FieldDecl* D) {
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(),
StateMgr.getSymbolManager());
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));
}
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()) {
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,
StateMgr.getSymbolManager());
// Layered a typed region on top of this.
QualType T = StateMgr.getSymbolManager().getType(Sym);
BaseR = MRMgr.getTypedViewRegion(T, SymR);
break;
}
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();
}
SVal BasicStoreManager::Retrieve(const GRState* state, Loc loc, QualType T) {
if (isa<UnknownVal>(loc))
return UnknownVal();
assert (!isa<UndefinedVal>(loc));
switch (loc.getSubKind()) {
case loc::MemRegionKind: {
const VarRegion* R =
dyn_cast<VarRegion>(cast<loc::MemRegionVal>(loc).getRegion());
if (!R)
return UnknownVal();
Store store = state->getStore();
2008-12-21 11:46:11 +08:00
VarBindingsTy B = GetVarBindings(store);
VarBindingsTy::data_type* T = B.lookup(R->getDecl());
return T ? *T : UnknownVal();
}
case loc::SymbolValKind:
return UnknownVal();
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.
return UndefinedVal();
case loc::FuncValKind:
return loc;
default:
assert (false && "Invalid Loc.");
break;
}
return UnknownVal();
}
Store BasicStoreManager::BindInternal(Store store, Loc loc, SVal V) {
switch (loc.getSubKind()) {
case loc::MemRegionKind: {
const VarRegion* R =
dyn_cast<VarRegion>(cast<loc::MemRegionVal>(loc).getRegion());
if (!R)
return store;
VarBindingsTy B = GetVarBindings(store);
return V.isUnknown()
? VBFactory.Remove(B, R->getDecl()).getRoot()
: VBFactory.Add(B, R->getDecl(), V).getRoot();
}
default:
assert ("SetSVal for given Loc type not yet implemented.");
return store;
}
}
Store BasicStoreManager::Remove(Store store, Loc loc) {
switch (loc.getSubKind()) {
case loc::MemRegionKind: {
const VarRegion* R =
dyn_cast<VarRegion>(cast<loc::MemRegionVal>(loc).getRegion());
if (!R)
return store;
VarBindingsTy B = GetVarBindings(store);
return VBFactory.Remove(B,R->getDecl()).getRoot();
}
default:
assert ("Remove for given Loc type not yet implemented.");
return store;
}
}
Store
BasicStoreManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
{
Store store = state->getStore();
VarBindingsTy B = GetVarBindings(store);
typedef SVal::symbol_iterator symbol_iterator;
// Iterate over the variable bindings.
for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I)
if (SymReaper.isLive(Loc, I.getKey())) {
RegionRoots.push_back(MRMgr.getVarRegion(I.getKey()));
SVal X = I.getData();
for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
SymReaper.markLive(*SI);
}
// Scan for live variables and live symbols.
llvm::SmallPtrSet<const VarRegion*, 10> Marked;
while (!RegionRoots.empty()) {
const MemRegion* MR = RegionRoots.back();
RegionRoots.pop_back();
while (MR) {
if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(MR)) {
SymReaper.markLive(SymR->getSymbol());
break;
}
else if (const VarRegion* R = dyn_cast<VarRegion>(MR)) {
if (Marked.count(R))
break;
Marked.insert(R);
SVal X = Retrieve(state, loc::MemRegionVal(R));
// FIXME: We need to handle symbols nested in region definitions.
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.
for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) {
const VarRegion* R = cast<VarRegion>(MRMgr.getVarRegion(I.getKey()));
if (!Marked.count(R)) {
store = Remove(store, Loc::MakeVal(R));
SVal X = I.getData();
for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
SymReaper.maybeDead(*SI);
}
}
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();
if (Loc::IsLocType(T) || T->isIntegerType()) {
// Initialize globals and parameters to symbolic values.
// Initialize local variables to undefined.
const MemRegion *R = StateMgr.getRegion(VD);
SVal X = (VD->hasGlobalStorage() || isa<ParmVarDecl>(VD) ||
isa<ImplicitParamDecl>(VD))
? SVal::GetRValueSymbolVal(StateMgr.getSymbolManager(), R)
: UndefinedVal();
St = BindInternal(St, Loc::MakeVal(R), X);
}
}
}
return St;
}
Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD,
SVal* InitVal) {
BasicValueFactory& BasicVals = StateMgr.getBasicVals();
// 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;
if (!InitVal) {
QualType T = VD->getType();
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();
if (Loc::IsLocType(T) || T->isIntegerType()) {
SVal V = InitVal ? *InitVal : UndefinedVal();
store = BindInternal(store, getLoc(VD), V);
}
}
return store;
}
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() << " : ";
I.getData().print(Out);
}
}
void BasicStoreManager::iterBindings(Store store, BindingsHandler& f) {
VarBindingsTy B = GetVarBindings(store);
for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {
f.HandleBinding(*this, store, MRMgr.getVarRegion(I.getKey()),I.getData());
}
}
StoreManager::BindingsHandler::~BindingsHandler() {}