forked from OSchip/llvm-project
Store: (static analyzer)
- Change definition of store::Region and store::Binding (once again) to make them real classes that just wrap pointers. This makes them more strictly typed, and allows specific implementations of Regions/Bindings to just subclass them. - minor renamings to RegionExtent and its subclasses - added a bunch of doxygen comments StoreManager: (static analyzer) - added 'iterBindings', an iteration method for iterating over the bindings of a store. It that takes a callback object (acting like a poor man's closure). - added 'getRVal' version for store::Binding. Will potentially phase the other versions of GetRVal in StoreManager out. - reimplemented 'getBindings' to be non-virtual and to use 'iterBindings' BasicStoreManager: (static analyzer) - implemented 'iterBindings' for BasicStoreManager llvm-svn: 55688
This commit is contained in:
parent
2175b55dc7
commit
1b9e10390b
|
@ -27,12 +27,38 @@ namespace clang {
|
||||||
typedef const void* Store;
|
typedef const void* Store;
|
||||||
|
|
||||||
namespace store {
|
namespace store {
|
||||||
typedef const void* Binding;
|
/// Region - A region represents an abstract chunk of memory. Subclasses
|
||||||
typedef const void* Region;
|
/// of StoreManager are responsible for defining the particular semantics
|
||||||
|
/// of Region for the store they represent.
|
||||||
|
class Region {
|
||||||
|
protected:
|
||||||
|
const void* Data;
|
||||||
|
Region(const void* data) : Data(data) {}
|
||||||
|
public:
|
||||||
|
Region() : Data(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Binding - A "binding" represents a binding of a value to an abstract
|
||||||
|
/// chunk of memory (which is represented by a region). Subclasses of
|
||||||
|
/// StoreManager are responsible for defining the particular semantics
|
||||||
|
/// of a Binding.
|
||||||
|
class Binding {
|
||||||
|
protected:
|
||||||
|
const void* first;
|
||||||
|
const void* second;
|
||||||
|
Binding(const void* f, const void* s = 0) : first(f), second(s) {}
|
||||||
|
public:
|
||||||
|
Binding() : first(0), second(0) {}
|
||||||
|
operator bool() const { return first || second; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// RegionExtent - Represents the size, or extent, or an abstract memory
|
||||||
|
/// chunk (a region). Sizes are in bits. RegionExtent is essentially a
|
||||||
|
/// variant with three subclasses: UnknownExtent, FixedExtent,
|
||||||
|
/// and SymbolicExtent.
|
||||||
class RegionExtent {
|
class RegionExtent {
|
||||||
public:
|
public:
|
||||||
enum Kind { Unknown = 0, Int = 0, Sym = 1 };
|
enum Kind { Unknown = 0, Fixed = 0, Sym = 1 };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const uintptr_t Raw;
|
const uintptr_t Raw;
|
||||||
|
@ -60,6 +86,8 @@ namespace store {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// UnknownExtent - Represents a region extent with no available information
|
||||||
|
/// about the size of the region.
|
||||||
class UnknownExtent : public RegionExtent {
|
class UnknownExtent : public RegionExtent {
|
||||||
public:
|
public:
|
||||||
UnknownExtent() : RegionExtent(0,Unknown) {}
|
UnknownExtent() : RegionExtent(0,Unknown) {}
|
||||||
|
@ -70,9 +98,12 @@ namespace store {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class IntExtent : public RegionExtent {
|
/// FixedExtent - Represents a region extent with a known fixed size.
|
||||||
|
/// Typically FixedExtents are used to represent the size of variables, but
|
||||||
|
/// they can also be used to represent the size of a constant-sized array.
|
||||||
|
class FixedExtent : public RegionExtent {
|
||||||
public:
|
public:
|
||||||
IntExtent(const llvm::APSInt& X) : RegionExtent((uintptr_t) &X, Int) {}
|
FixedExtent(const llvm::APSInt& X) : RegionExtent((uintptr_t) &X, Fixed) {}
|
||||||
|
|
||||||
const llvm::APSInt& getInt() const {
|
const llvm::APSInt& getInt() const {
|
||||||
return *((llvm::APSInt*) getData());
|
return *((llvm::APSInt*) getData());
|
||||||
|
@ -80,13 +111,16 @@ namespace store {
|
||||||
|
|
||||||
// Implement isa<T> support.
|
// Implement isa<T> support.
|
||||||
static inline bool classof(const RegionExtent* E) {
|
static inline bool classof(const RegionExtent* E) {
|
||||||
return E->getKind() == Int && E->getRaw() != 0;
|
return E->getKind() == Fixed && E->getRaw() != 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SymExtent : public RegionExtent {
|
/// SymbolicExtent - Represents the extent of a region where the extent
|
||||||
|
/// itself is a symbolic value. These extents can be used to represent
|
||||||
|
/// the sizes of dynamically allocated chunks of memory with variable size.
|
||||||
|
class SymbolicExtent : public RegionExtent {
|
||||||
public:
|
public:
|
||||||
SymExtent(SymbolID S) : RegionExtent(S.getNumber() << 1, Sym) {}
|
SymbolicExtent(SymbolID S) : RegionExtent(S.getNumber() << 1, Sym) {}
|
||||||
|
|
||||||
SymbolID getSymbol() const { return SymbolID(getData() >> 1); }
|
SymbolID getSymbol() const { return SymbolID(getData() >> 1); }
|
||||||
|
|
||||||
|
@ -124,17 +158,30 @@ public:
|
||||||
|
|
||||||
virtual void print(Store store, std::ostream& Out,
|
virtual void print(Store store, std::ostream& Out,
|
||||||
const char* nl, const char *sep) = 0;
|
const char* nl, const char *sep) = 0;
|
||||||
|
|
||||||
|
class BindingsHandler {
|
||||||
|
public:
|
||||||
|
virtual ~BindingsHandler();
|
||||||
|
virtual bool HandleBinding(StoreManager& SMgr, Store store,
|
||||||
|
store::Binding binding) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// iterBindings - Iterate over the bindings in the Store.
|
||||||
|
virtual void iterBindings(Store store, BindingsHandler& f) = 0;
|
||||||
|
|
||||||
/// getBindings - Returns all bindings in the specified store that bind
|
/// getBindings - Returns all bindings in the specified store that bind
|
||||||
/// to the specified symbolic value.
|
/// to the specified symbolic value.
|
||||||
virtual void getBindings(llvm::SmallVectorImpl<store::Binding>& bindings,
|
void getBindings(llvm::SmallVectorImpl<store::Binding>& bindings,
|
||||||
Store store, SymbolID Sym) = 0;
|
Store store, SymbolID Sym);
|
||||||
|
|
||||||
/// BindingAsString - Returns a string representing the given binding.
|
/// BindingAsString - Returns a string representing the given binding.
|
||||||
virtual std::string BindingAsString(store::Binding binding) = 0;
|
virtual std::string BindingAsString(store::Binding binding) = 0;
|
||||||
|
|
||||||
/// getExtent - Returns the size of the region in bits.
|
/// getExtent - Returns the size of the region in bits.
|
||||||
virtual store::RegionExtent getExtent(store::Region R) =0;
|
virtual store::RegionExtent getExtent(store::Region R) = 0;
|
||||||
|
|
||||||
|
/// getRVal - Returns the bound RVal for a given binding.
|
||||||
|
virtual RVal getRVal(Store store, store::Binding binding) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
StoreManager* CreateBasicStoreManager(GRStateManager& StMgr);
|
StoreManager* CreateBasicStoreManager(GRStateManager& StMgr);
|
||||||
|
|
|
@ -21,10 +21,11 @@ using namespace clang;
|
||||||
using store::Region;
|
using store::Region;
|
||||||
using store::RegionExtent;
|
using store::RegionExtent;
|
||||||
|
|
||||||
|
typedef llvm::ImmutableMap<VarDecl*,RVal> VarBindingsTy;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager {
|
class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager {
|
||||||
typedef llvm::ImmutableMap<VarDecl*,RVal> VarBindingsTy;
|
|
||||||
VarBindingsTy::Factory VBFactory;
|
VarBindingsTy::Factory VBFactory;
|
||||||
GRStateManager& StMgr;
|
GRStateManager& StMgr;
|
||||||
|
|
||||||
|
@ -44,6 +45,8 @@ public:
|
||||||
DeclRootsTy& DRoots, LiveSymbolsTy& LSymbols,
|
DeclRootsTy& DRoots, LiveSymbolsTy& LSymbols,
|
||||||
DeadSymbolsTy& DSymbols);
|
DeadSymbolsTy& DSymbols);
|
||||||
|
|
||||||
|
virtual void iterBindings(Store store, BindingsHandler& f);
|
||||||
|
|
||||||
virtual Store AddDecl(Store store, GRStateManager& StateMgr,
|
virtual Store AddDecl(Store store, GRStateManager& StateMgr,
|
||||||
const VarDecl* VD, Expr* Ex,
|
const VarDecl* VD, Expr* Ex,
|
||||||
RVal InitVal = UndefinedVal(), unsigned Count = 0);
|
RVal InitVal = UndefinedVal(), unsigned Count = 0);
|
||||||
|
@ -57,14 +60,38 @@ public:
|
||||||
|
|
||||||
virtual RegionExtent getExtent(Region R);
|
virtual RegionExtent getExtent(Region R);
|
||||||
|
|
||||||
/// getBindings - Returns all bindings in the specified store that bind
|
|
||||||
/// to the specified symbolic value.
|
|
||||||
virtual void getBindings(llvm::SmallVectorImpl<store::Binding>& bindings,
|
|
||||||
Store store, SymbolID Sym);
|
|
||||||
|
|
||||||
/// BindingAsString - Returns a string representing the given binding.
|
/// BindingAsString - Returns a string representing the given binding.
|
||||||
virtual std::string BindingAsString(store::Binding binding);
|
virtual std::string BindingAsString(store::Binding binding);
|
||||||
};
|
|
||||||
|
/// getRVal - Returns the bound RVal for a given binding.
|
||||||
|
virtual RVal getRVal(Store store, store::Binding binding);
|
||||||
|
};
|
||||||
|
|
||||||
|
class VISIBILITY_HIDDEN VarRegion : public store::Region {
|
||||||
|
public:
|
||||||
|
VarRegion(VarDecl* VD) : Region(VD) {}
|
||||||
|
VarDecl* getDecl() const { return (VarDecl*) Data; }
|
||||||
|
static bool classof(const store::Region*) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class VISIBILITY_HIDDEN VarBinding : public store::Binding {
|
||||||
|
public:
|
||||||
|
VarBinding(VarBindingsTy::value_type* T) : store::Binding(T) {}
|
||||||
|
|
||||||
|
const VarBindingsTy::value_type_ref getValue() const {
|
||||||
|
return *static_cast<const VarBindingsTy::value_type*>(first);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getName() const {
|
||||||
|
return getValue().first->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
RVal getRVal() const {
|
||||||
|
return getValue().second;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool classof(const store::Binding*) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
@ -74,8 +101,7 @@ StoreManager* clang::CreateBasicStoreManager(GRStateManager& StMgr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
RegionExtent BasicStoreManager::getExtent(Region R) {
|
RegionExtent BasicStoreManager::getExtent(Region R) {
|
||||||
VarDecl* VD = (VarDecl*) R;
|
QualType T = cast<VarRegion>(&R)->getDecl()->getType();
|
||||||
QualType T = VD->getType();
|
|
||||||
|
|
||||||
// FIXME: Add support for VLAs. This may require passing in additional
|
// FIXME: Add support for VLAs. This may require passing in additional
|
||||||
// information, or tracking a different region type.
|
// information, or tracking a different region type.
|
||||||
|
@ -85,8 +111,8 @@ RegionExtent BasicStoreManager::getExtent(Region R) {
|
||||||
ASTContext& C = StMgr.getContext();
|
ASTContext& C = StMgr.getContext();
|
||||||
assert (!T->isObjCInterfaceType()); // @interface not a possible VarDecl type.
|
assert (!T->isObjCInterfaceType()); // @interface not a possible VarDecl type.
|
||||||
assert (T != C.VoidTy); // void not a possible VarDecl type.
|
assert (T != C.VoidTy); // void not a possible VarDecl type.
|
||||||
return store::IntExtent(StMgr.getBasicVals().getValue(C.getTypeSize(T),
|
return store::FixedExtent(StMgr.getBasicVals().getValue(C.getTypeSize(T),
|
||||||
C.VoidPtrTy));
|
C.VoidPtrTy));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -335,28 +361,62 @@ void BasicStoreManager::print(Store store, std::ostream& Out,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
BasicStoreManager::getBindings(llvm::SmallVectorImpl<store::Binding>& bindings,
|
void BasicStoreManager::iterBindings(Store store, BindingsHandler& f) {
|
||||||
Store store, SymbolID Sym) {
|
VarBindingsTy B = GetVarBindings(store);
|
||||||
|
|
||||||
VarBindingsTy VB((VarBindingsTy::TreeTy*) store);
|
for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {
|
||||||
|
VarBinding binding(&(*I));
|
||||||
for (VarBindingsTy::iterator I=VB.begin(), E=VB.end(); I!=E; ++I) {
|
f.HandleBinding(*this, store, binding);
|
||||||
if (const lval::SymbolVal* SV=dyn_cast<lval::SymbolVal>(&I->second)) {
|
|
||||||
if (SV->getSymbol() == Sym)
|
|
||||||
bindings.push_back(I->first);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const nonlval::SymbolVal* SV=dyn_cast<nonlval::SymbolVal>(&I->second)){
|
|
||||||
if (SV->getSymbol() == Sym)
|
|
||||||
bindings.push_back(I->first);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string BasicStoreManager::BindingAsString(store::Binding binding) {
|
std::string BasicStoreManager::BindingAsString(store::Binding binding) {
|
||||||
// A binding is just an VarDecl*.
|
return cast<VarBinding>(binding).getName();
|
||||||
return ((VarDecl*) binding)->getName();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RVal BasicStoreManager::getRVal(Store store, store::Binding binding) {
|
||||||
|
return cast<VarBinding>(binding).getRVal();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==------------------------------------------------------------------------==//
|
||||||
|
// Generic store operations.
|
||||||
|
//==------------------------------------------------------------------------==//
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class VISIBILITY_HIDDEN GetBindingsIterator : public StoreManager::BindingsHandler {
|
||||||
|
SymbolID Sym;
|
||||||
|
llvm::SmallVectorImpl<store::Binding>& bindings;
|
||||||
|
public:
|
||||||
|
GetBindingsIterator(SymbolID s, llvm::SmallVectorImpl<store::Binding>& b)
|
||||||
|
: Sym(s), bindings(b) {}
|
||||||
|
|
||||||
|
virtual bool HandleBinding(StoreManager& SMgr, Store store,
|
||||||
|
store::Binding binding) {
|
||||||
|
|
||||||
|
RVal V = SMgr.getRVal(store, binding);
|
||||||
|
|
||||||
|
if (const lval::SymbolVal* SV=dyn_cast<lval::SymbolVal>(&V)) {
|
||||||
|
if (SV->getSymbol() == Sym)
|
||||||
|
bindings.push_back(binding);
|
||||||
|
}
|
||||||
|
else if (const nonlval::SymbolVal* SV=dyn_cast<nonlval::SymbolVal>(&V)){
|
||||||
|
if (SV->getSymbol() == Sym)
|
||||||
|
bindings.push_back(binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
void StoreManager::getBindings(llvm::SmallVectorImpl<store::Binding>& bindings,
|
||||||
|
Store store, SymbolID Sym) {
|
||||||
|
|
||||||
|
GetBindingsIterator BI(Sym, bindings);
|
||||||
|
iterBindings(store, BI);
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreManager::BindingsHandler::~BindingsHandler() {}
|
||||||
|
|
||||||
|
|
|
@ -2308,7 +2308,7 @@ GetAllocationSite(GRStateManager* StateMgr, ExplodedNode<GRState>* N,
|
||||||
// Find both first node that referred to the tracked symbol and the
|
// Find both first node that referred to the tracked symbol and the
|
||||||
// memory location that value was store to.
|
// memory location that value was store to.
|
||||||
ExplodedNode<GRState>* Last = N;
|
ExplodedNode<GRState>* Last = N;
|
||||||
store::Binding FirstBinding = 0;
|
store::Binding FirstBinding;
|
||||||
|
|
||||||
while (N) {
|
while (N) {
|
||||||
const GRState* St = N->getState();
|
const GRState* St = N->getState();
|
||||||
|
@ -2351,7 +2351,7 @@ PathDiagnosticPiece* CFRefReport::getEndPath(BugReporter& br,
|
||||||
// symbol appeared, and also get the first VarDecl that tracked object
|
// symbol appeared, and also get the first VarDecl that tracked object
|
||||||
// is stored to.
|
// is stored to.
|
||||||
ExplodedNode<GRState>* AllocNode = 0;
|
ExplodedNode<GRState>* AllocNode = 0;
|
||||||
store::Binding FirstBinding = 0;
|
store::Binding FirstBinding;
|
||||||
|
|
||||||
llvm::tie(AllocNode, FirstBinding) =
|
llvm::tie(AllocNode, FirstBinding) =
|
||||||
GetAllocationSite(&BR.getStateManager(), EndN, Sym);
|
GetAllocationSite(&BR.getStateManager(), EndN, Sym);
|
||||||
|
|
Loading…
Reference in New Issue