diff options
-rw-r--r-- | include/clang/Analysis/PathSensitive/Store.h | 71 | ||||
-rw-r--r-- | lib/Analysis/BasicStore.cpp | 116 | ||||
-rw-r--r-- | lib/Analysis/CFRefCount.cpp | 4 |
3 files changed, 149 insertions, 42 deletions
diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Analysis/PathSensitive/Store.h index d91dac1fe4..fc9b7f3d07 100644 --- a/include/clang/Analysis/PathSensitive/Store.h +++ b/include/clang/Analysis/PathSensitive/Store.h @@ -27,12 +27,38 @@ namespace clang { typedef const void* Store; namespace store { - typedef const void* Binding; - typedef const void* Region; + /// Region - A region represents an abstract chunk of memory. Subclasses + /// 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 { public: - enum Kind { Unknown = 0, Int = 0, Sym = 1 }; + enum Kind { Unknown = 0, Fixed = 0, Sym = 1 }; protected: 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 { public: 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: - 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 { return *((llvm::APSInt*) getData()); @@ -80,13 +111,16 @@ namespace store { // Implement isa<T> support. 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: - SymExtent(SymbolID S) : RegionExtent(S.getNumber() << 1, Sym) {} + SymbolicExtent(SymbolID S) : RegionExtent(S.getNumber() << 1, Sym) {} SymbolID getSymbol() const { return SymbolID(getData() >> 1); } @@ -124,17 +158,30 @@ public: virtual void print(Store store, std::ostream& Out, 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 /// to the specified symbolic value. - virtual void getBindings(llvm::SmallVectorImpl<store::Binding>& bindings, - Store store, SymbolID Sym) = 0; + void getBindings(llvm::SmallVectorImpl<store::Binding>& bindings, + Store store, SymbolID Sym); /// BindingAsString - Returns a string representing the given binding. virtual std::string BindingAsString(store::Binding binding) = 0; /// 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); diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp index 867028dc19..97566798c0 100644 --- a/lib/Analysis/BasicStore.cpp +++ b/lib/Analysis/BasicStore.cpp @@ -21,10 +21,11 @@ using namespace clang; using store::Region; using store::RegionExtent; +typedef llvm::ImmutableMap<VarDecl*,RVal> VarBindingsTy; + namespace { class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager { - typedef llvm::ImmutableMap<VarDecl*,RVal> VarBindingsTy; VarBindingsTy::Factory VBFactory; GRStateManager& StMgr; @@ -44,6 +45,8 @@ public: DeclRootsTy& DRoots, LiveSymbolsTy& LSymbols, DeadSymbolsTy& DSymbols); + virtual void iterBindings(Store store, BindingsHandler& f); + virtual Store AddDecl(Store store, GRStateManager& StateMgr, const VarDecl* VD, Expr* Ex, RVal InitVal = UndefinedVal(), unsigned Count = 0); @@ -57,14 +60,38 @@ public: 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. 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 @@ -74,8 +101,7 @@ StoreManager* clang::CreateBasicStoreManager(GRStateManager& StMgr) { } RegionExtent BasicStoreManager::getExtent(Region R) { - VarDecl* VD = (VarDecl*) R; - QualType T = VD->getType(); + QualType T = cast<VarRegion>(&R)->getDecl()->getType(); // FIXME: Add support for VLAs. This may require passing in additional // information, or tracking a different region type. @@ -85,8 +111,8 @@ RegionExtent BasicStoreManager::getExtent(Region R) { ASTContext& C = StMgr.getContext(); assert (!T->isObjCInterfaceType()); // @interface not a possible VarDecl type. assert (T != C.VoidTy); // void not a possible VarDecl type. - return store::IntExtent(StMgr.getBasicVals().getValue(C.getTypeSize(T), - C.VoidPtrTy)); + return store::FixedExtent(StMgr.getBasicVals().getValue(C.getTypeSize(T), + C.VoidPtrTy)); } @@ -335,28 +361,62 @@ void BasicStoreManager::print(Store store, std::ostream& Out, } } -void -BasicStoreManager::getBindings(llvm::SmallVectorImpl<store::Binding>& bindings, - Store store, SymbolID Sym) { + +void BasicStoreManager::iterBindings(Store store, BindingsHandler& f) { + VarBindingsTy B = GetVarBindings(store); - VarBindingsTy VB((VarBindingsTy::TreeTy*) store); + for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) { + VarBinding binding(&(*I)); + f.HandleBinding(*this, store, binding); + } +} + + +std::string BasicStoreManager::BindingAsString(store::Binding binding) { + return cast<VarBinding>(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) {} - for (VarBindingsTy::iterator I=VB.begin(), E=VB.end(); I!=E; ++I) { - if (const lval::SymbolVal* SV=dyn_cast<lval::SymbolVal>(&I->second)) { - if (SV->getSymbol() == Sym) - bindings.push_back(I->first); - - continue; - } + virtual bool HandleBinding(StoreManager& SMgr, Store store, + store::Binding binding) { + + RVal V = SMgr.getRVal(store, binding); - if (const nonlval::SymbolVal* SV=dyn_cast<nonlval::SymbolVal>(&I->second)){ + 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(I->first); + bindings.push_back(binding); } + + return true; } -} +}; +} // end anonymous namespace -std::string BasicStoreManager::BindingAsString(store::Binding binding) { - // A binding is just an VarDecl*. - return ((VarDecl*) binding)->getName(); +void StoreManager::getBindings(llvm::SmallVectorImpl<store::Binding>& bindings, + Store store, SymbolID Sym) { + + GetBindingsIterator BI(Sym, bindings); + iterBindings(store, BI); } + +StoreManager::BindingsHandler::~BindingsHandler() {} + diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 8ea8301134..25841cd8db 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -2308,7 +2308,7 @@ GetAllocationSite(GRStateManager* StateMgr, ExplodedNode<GRState>* N, // Find both first node that referred to the tracked symbol and the // memory location that value was store to. ExplodedNode<GRState>* Last = N; - store::Binding FirstBinding = 0; + store::Binding FirstBinding; while (N) { 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 // is stored to. ExplodedNode<GRState>* AllocNode = 0; - store::Binding FirstBinding = 0; + store::Binding FirstBinding; llvm::tie(AllocNode, FirstBinding) = GetAllocationSite(&BR.getStateManager(), EndN, Sym); |