diff options
-rw-r--r-- | include/clang/Analysis/PathSensitive/GRState.h | 8 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/MemRegion.h | 83 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/RValues.h | 7 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/Store.h | 10 | ||||
-rw-r--r-- | lib/Analysis/BasicObjCFoundationChecks.cpp | 6 | ||||
-rw-r--r-- | lib/Analysis/BasicStore.cpp | 44 | ||||
-rw-r--r-- | lib/Analysis/CFRefCount.cpp | 4 | ||||
-rw-r--r-- | lib/Analysis/CheckNSError.cpp | 6 | ||||
-rw-r--r-- | lib/Analysis/MemRegion.cpp | 56 | ||||
-rw-r--r-- | lib/Analysis/RegionStore.cpp | 2 |
10 files changed, 178 insertions, 48 deletions
diff --git a/include/clang/Analysis/PathSensitive/GRState.h b/include/clang/Analysis/PathSensitive/GRState.h index 331c8301cd..cd0ae39f88 100644 --- a/include/clang/Analysis/PathSensitive/GRState.h +++ b/include/clang/Analysis/PathSensitive/GRState.h @@ -425,6 +425,10 @@ public: return StoreMgr->GetSVal(St->getStore(), LV, T); } + SVal GetSVal(const GRState* St, const MemRegion* R) { + return StoreMgr->GetRegionSVal(St->getStore(), R); + } + void SetSVal(GRState& St, Loc LV, SVal V) { St.St = StoreMgr->SetSVal(St.St, LV, V); } @@ -522,6 +526,10 @@ public: return Mgr->GetSVal(St, LV, T); } + SVal GetSVal(const MemRegion* R) { + return Mgr->GetSVal(St, R); + } + GRStateRef SetSVal(Expr* Ex, SVal V, bool isBlkExpr, bool Invalidate) { return GRStateRef(Mgr->SetSVal(St, Ex, V, isBlkExpr, Invalidate), *Mgr); } diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h index a1e02b0e98..fddf40d2e9 100644 --- a/include/clang/Analysis/PathSensitive/MemRegion.h +++ b/include/clang/Analysis/PathSensitive/MemRegion.h @@ -16,11 +16,12 @@ #ifndef LLVM_CLANG_ANALYSIS_MEMREGION_H #define LLVM_CLANG_ANALYSIS_MEMREGION_H +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Analysis/PathSensitive/SymbolManager.h" #include "llvm/Support/Casting.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/Support/Allocator.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclObjC.h" #include <string> namespace llvm { class raw_ostream; } @@ -33,7 +34,7 @@ class MemRegionManager; /// MemRegion - The root abstract class for all memory regions. class MemRegion : public llvm::FoldingSetNode { public: - enum Kind { MemSpaceRegionKind, + enum Kind { MemSpaceRegionKind, SymbolicRegionKind, // Typed regions. BEG_TYPED_REGIONS, VarRegionKind, FieldRegionKind, ObjCIvarRegionKind, @@ -48,7 +49,6 @@ protected: public: // virtual MemExtent getExtent(MemRegionManager& mrm) const = 0; - virtual const MemRegion* getSuperRegion() const = 0; virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0; std::string getString() const; @@ -67,11 +67,6 @@ class MemSpaceRegion : public MemRegion { public: //RegionExtent getExtent() const { return UndefinedExtent(); } - const MemRegion* getSuperRegion() const { - return 0; - } - - //static void ProfileRegion(llvm::FoldingSetNodeID& ID); void Profile(llvm::FoldingSetNodeID& ID) const; static bool classof(const MemRegion* R) { @@ -79,23 +74,58 @@ public: } }; -/// TypedRegion - An abstract class representing regions that are typed. -class TypedRegion : public MemRegion { +/// SubRegion - A region that subsets another larger region. Most regions +/// are subclasses of SubRegion. +class SubRegion : public MemRegion { protected: - const MemRegion* superRegion; - - TypedRegion(const MemRegion* sReg, Kind k) - : MemRegion(k), superRegion(sReg) {}; + const MemRegion* superRegion; + SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {} public: - virtual QualType getType() const = 0; - - // MemExtent getExtent(MemRegionManager& mrm) const; const MemRegion* getSuperRegion() const { return superRegion; } static bool classof(const MemRegion* R) { + return R->getKind() > SymbolicRegionKind; + } +}; + +/// SymbolicRegion - A special, "non-concrete" region. Unlike other region +/// clases, SymbolicRegion represents a region that serves as an alias for +/// either a real region, a NULL pointer, etc. It essentially is used to +/// map the concept of symbolic values into the domain of regions. Symbolic +/// regions do not need to be typed. +class SymbolicRegion : public MemRegion { +protected: + const SymbolID sym; + +public: + SymbolicRegion(const SymbolID s) : MemRegion(SymbolicRegionKind), sym(s) {} + + SymbolID getSymbol() const { + return sym; + } + + void Profile(llvm::FoldingSetNodeID& ID) const; + static void ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolID sym); + + void print(llvm::raw_ostream& os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == SymbolicRegionKind; + } +}; + +/// TypedRegion - An abstract class representing regions that are typed. +class TypedRegion : public SubRegion { +protected: + TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {} + +public: + virtual QualType getType() const = 0; + + static bool classof(const MemRegion* R) { unsigned k = R->getKind(); return k > BEG_TYPED_REGIONS && k < END_TYPED_REGIONS; } @@ -152,7 +182,7 @@ class DeclRegion : public TypedRegion { protected: const Decl* D; - DeclRegion(const Decl* d, MemRegion* sReg, Kind k) + DeclRegion(const Decl* d, const MemRegion* sReg, Kind k) : TypedRegion(sReg, k), D(d) {} static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D, @@ -165,7 +195,7 @@ public: class VarRegion : public DeclRegion { friend class MemRegionManager; - VarRegion(const VarDecl* vd, MemRegion* sReg) + VarRegion(const VarDecl* vd, const MemRegion* sReg) : DeclRegion(vd, sReg, VarRegionKind) {} static void ProfileRegion(llvm::FoldingSetNodeID& ID, VarDecl* VD, @@ -187,7 +217,7 @@ public: class FieldRegion : public DeclRegion { friend class MemRegionManager; - FieldRegion(const FieldDecl* fd, MemRegion* sReg) + FieldRegion(const FieldDecl* fd, const MemRegion* sReg) : DeclRegion(fd, sReg, FieldRegionKind) {} static void ProfileRegion(llvm::FoldingSetNodeID& ID, FieldDecl* FD, @@ -208,7 +238,7 @@ class ObjCIvarRegion : public DeclRegion { friend class MemRegionManager; - ObjCIvarRegion(const ObjCIvarDecl* ivd, MemRegion* sReg) + ObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* sReg) : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {} static void ProfileRegion(llvm::FoldingSetNodeID& ID, ObjCIvarDecl* ivd, @@ -260,10 +290,13 @@ public: /// memory space. MemSpaceRegion* getUnknownRegion(); + /// getSymbolicRegion - Retrieve or create a "symbolic" memory region. + SymbolicRegion* getSymbolicRegion(const SymbolID sym); + /// getVarRegion - Retrieve or create the memory region associated with /// a specified VarDecl. 'superRegion' corresponds to the containing /// memory region, and 'off' is the offset within the containing region. - VarRegion* getVarRegion(const VarDecl* vd, MemRegion* superRegion); + VarRegion* getVarRegion(const VarDecl* vd, const MemRegion* superRegion); VarRegion* getVarRegion(const VarDecl* vd) { return getVarRegion(vd, vd->hasLocalStorage() ? getStackRegion() @@ -274,14 +307,14 @@ public: /// a specified FieldDecl. 'superRegion' corresponds to the containing /// memory region (which typically represents the memory representing /// a structure or class). - FieldRegion* getFieldRegion(const FieldDecl* fd, MemRegion* superRegion); + FieldRegion* getFieldRegion(const FieldDecl* fd, const MemRegion* superRegion); /// getObjCIvarRegion - Retrieve or create the memory region associated with /// a specified Objective-c instance variable. 'superRegion' corresponds /// to the containing region (which typically represents the Objective-C /// object). ObjCIvarRegion* getObjCIvarRegion(const ObjCIvarDecl* ivd, - MemRegion* superRegion); + const MemRegion* superRegion); AnonPointeeRegion* getAnonPointeeRegion(const VarDecl* d); diff --git a/include/clang/Analysis/PathSensitive/RValues.h b/include/clang/Analysis/PathSensitive/RValues.h index c1ee0e0e90..3466b9b001 100644 --- a/include/clang/Analysis/PathSensitive/RValues.h +++ b/include/clang/Analysis/PathSensitive/RValues.h @@ -331,10 +331,15 @@ class MemRegionVal : public Loc { public: MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {} - MemRegion* getRegion() const { + const MemRegion* getRegion() const { return static_cast<MemRegion*>(Data); } + template <typename REGION> + const REGION* getRegionAs() const { + return llvm::dyn_cast<REGION>(getRegion()); + } + inline bool operator==(const MemRegionVal& R) const { return getRegion() == R.getRegion(); } diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Analysis/PathSensitive/Store.h index 3acb789a24..b6d4be3b66 100644 --- a/include/clang/Analysis/PathSensitive/Store.h +++ b/include/clang/Analysis/PathSensitive/Store.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_ANALYSIS_STORE_H #include "clang/Analysis/PathSensitive/RValues.h" +#include "clang/Analysis/PathSensitive/MemRegion.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/DenseSet.h" @@ -31,8 +32,6 @@ class LiveVariables; class Stmt; class Expr; class ObjCIvarDecl; -class MemRegion; -class MemRegionManager; class StoreManager { public: @@ -40,7 +39,12 @@ public: typedef llvm::DenseSet<SymbolID> DeadSymbolsTy; virtual ~StoreManager() {} - virtual SVal GetSVal(Store St, Loc LV, QualType T = QualType()) = 0; + virtual SVal GetSVal(Store St, Loc LV, QualType T = QualType()) = 0; + + virtual SVal GetRegionSVal(Store St, const MemRegion* R) { + return GetSVal(St, loc::MemRegionVal(R)); + } + virtual Store SetSVal(Store St, Loc LV, SVal V) = 0; virtual Store Remove(Store St, Loc LV) = 0; virtual Store getInitialStore() = 0; diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp index 8e322189e6..96a7ea1c16 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/lib/Analysis/BasicObjCFoundationChecks.cpp @@ -367,7 +367,7 @@ public: private: - void AddError(TypedRegion* R, Expr* Ex, ExplodedNode<GRState> *N, + void AddError(const TypedRegion* R, Expr* Ex, ExplodedNode<GRState> *N, uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind); }; } // end anonymous namespace @@ -503,7 +503,7 @@ bool AuditCFNumberCreate::Audit(ExplodedNode<GRState>* N,GRStateManager&){ if (!LV) return false; - TypedRegion* R = dyn_cast<TypedRegion>(LV->getRegion()); + const TypedRegion* R = dyn_cast<TypedRegion>(LV->getRegion()); if (!R) return false; @@ -530,7 +530,7 @@ bool AuditCFNumberCreate::Audit(ExplodedNode<GRState>* N,GRStateManager&){ return SourceSize < TargetSize; } -void AuditCFNumberCreate::AddError(TypedRegion* R, Expr* Ex, +void AuditCFNumberCreate::AddError(const TypedRegion* R, Expr* Ex, ExplodedNode<GRState> *N, uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind) { diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp index 7998ef4613..e1220ce674 100644 --- a/lib/Analysis/BasicStore.cpp +++ b/lib/Analysis/BasicStore.cpp @@ -90,7 +90,41 @@ SVal BasicStoreManager::getLValueIvar(const GRState* St, const ObjCIvarDecl* D, SVal BasicStoreManager::getLValueField(const GRState* St, const FieldDecl* D, SVal Base) { - return UnknownVal(); + + 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: + case loc::StringLiteralValKind: + // 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::MemRegionVal(MRMgr.getFieldRegion(D, BaseR)); } SVal BasicStoreManager::getLValueElement(const GRState* St, SVal Base, @@ -108,7 +142,7 @@ SVal BasicStoreManager::GetSVal(Store St, Loc LV, QualType T) { switch (LV.getSubKind()) { case loc::MemRegionKind: { - VarRegion* R = + const VarRegion* R = dyn_cast<VarRegion>(cast<loc::MemRegionVal>(LV).getRegion()); if (!R) @@ -145,7 +179,7 @@ SVal BasicStoreManager::GetSVal(Store St, Loc LV, QualType T) { Store BasicStoreManager::SetSVal(Store store, Loc LV, SVal V) { switch (LV.getSubKind()) { case loc::MemRegionKind: { - VarRegion* R = + const VarRegion* R = dyn_cast<VarRegion>(cast<loc::MemRegionVal>(LV).getRegion()); if (!R) @@ -165,8 +199,8 @@ Store BasicStoreManager::SetSVal(Store store, Loc LV, SVal V) { Store BasicStoreManager::Remove(Store store, Loc LV) { switch (LV.getSubKind()) { case loc::MemRegionKind: { - VarRegion* R = - dyn_cast<VarRegion>(cast<loc::MemRegionVal>(LV).getRegion()); + const VarRegion* R = + dyn_cast<VarRegion>(cast<loc::MemRegionVal>(LV).getRegion()); if (!R) return store; diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 9d632314b2..e720096aaf 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -1513,7 +1513,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst, state = state.remove<RefBindings>(Sym); } - TypedRegion* R = dyn_cast<TypedRegion>(MR->getRegion()); + const TypedRegion* R = dyn_cast<TypedRegion>(MR->getRegion()); if (R) { // Set the value of the variable to be a conjured symbol. unsigned Count = Builder.getCurrentBlockCount(); @@ -1717,7 +1717,7 @@ void CFRefCount::EvalStore(ExplodedNodeSet<GRState>& Dst, if (!isa<loc::MemRegionVal>(TargetLV)) escapes = true; else { - MemRegion* R = cast<loc::MemRegionVal>(TargetLV).getRegion(); + const MemRegion* R = cast<loc::MemRegionVal>(TargetLV).getRegion(); escapes = !Eng.getStateManager().hasStackStorage(R); } diff --git a/lib/Analysis/CheckNSError.cpp b/lib/Analysis/CheckNSError.cpp index 38d32a731d..f76b601e2d 100644 --- a/lib/Analysis/CheckNSError.cpp +++ b/lib/Analysis/CheckNSError.cpp @@ -216,7 +216,11 @@ void NSErrorCheck::CheckParamDeref(VarDecl* Param, GRStateRef rootState, GRExprEngine& Eng, GRBugReporter& BR, bool isNSErrorWarning) { - SVal ParamSVal = rootState.GetLValue(Param); + SVal ParamL = rootState.GetLValue(Param); + const MemRegion* ParamR = cast<loc::MemRegionVal>(ParamL).getRegionAs<VarRegion>(); + assert (ParamR && "Parameters always have VarRegions."); + SVal ParamSVal = rootState.GetSVal(ParamR); + // FIXME: For now assume that ParamSVal is symbolic. We need to generalize // this later. diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp index 747d2f6818..97a4fbc295 100644 --- a/lib/Analysis/MemRegion.cpp +++ b/lib/Analysis/MemRegion.cpp @@ -56,6 +56,15 @@ void DeclRegion::Profile(llvm::FoldingSetNodeID& ID) const { DeclRegion::ProfileRegion(ID, D, superRegion, getKind()); } +void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolID sym) { + ID.AddInteger((unsigned) MemRegion::SymbolicRegionKind); + ID.AddInteger(sym.getNumber()); +} + +void SymbolicRegion::Profile(llvm::FoldingSetNodeID& ID) const { + SymbolicRegion::ProfileRegion(ID, sym); +} + //===----------------------------------------------------------------------===// // Region pretty-printing. //===----------------------------------------------------------------------===// @@ -75,6 +84,10 @@ void VarRegion::print(llvm::raw_ostream& os) const { os << cast<VarDecl>(D)->getName(); } +void SymbolicRegion::print(llvm::raw_ostream& os) const { + os << "$" << sym.getNumber(); +} + //===----------------------------------------------------------------------===// // MemRegionManager methods. //===----------------------------------------------------------------------===// @@ -106,7 +119,7 @@ MemSpaceRegion* MemRegionManager::getUnknownRegion() { } VarRegion* MemRegionManager::getVarRegion(const VarDecl* d, - MemRegion* superRegion) { + const MemRegion* superRegion) { llvm::FoldingSetNodeID ID; DeclRegion::ProfileRegion(ID, d, superRegion, MemRegion::VarRegionKind); @@ -123,8 +136,27 @@ VarRegion* MemRegionManager::getVarRegion(const VarDecl* d, return R; } +/// getSymbolicRegion - Retrieve or create a "symbolic" memory region. +SymbolicRegion* MemRegionManager::getSymbolicRegion(const SymbolID sym) { + + llvm::FoldingSetNodeID ID; + SymbolicRegion::ProfileRegion(ID, sym); + + void* InsertPos; + MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos); + SymbolicRegion* R = cast_or_null<SymbolicRegion>(data); + + if (!R) { + R = (SymbolicRegion*) A.Allocate<SymbolicRegion>(); + new (R) SymbolicRegion(sym); + Regions.InsertNode(R, InsertPos); + } + + return R; +} + FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl* d, - MemRegion* superRegion) { + const MemRegion* superRegion) { llvm::FoldingSetNodeID ID; DeclRegion::ProfileRegion(ID, d, superRegion, MemRegion::FieldRegionKind); @@ -141,8 +173,9 @@ FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl* d, return R; } -ObjCIvarRegion* MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d, - MemRegion* superRegion) { +ObjCIvarRegion* +MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d, + const MemRegion* superRegion) { llvm::FoldingSetNodeID ID; DeclRegion::ProfileRegion(ID, d, superRegion, MemRegion::ObjCIvarRegionKind); @@ -181,11 +214,20 @@ AnonPointeeRegion* MemRegionManager::getAnonPointeeRegion(const VarDecl* d) { } bool MemRegionManager::hasStackStorage(const MemRegion* R) { + const SubRegion* SR = dyn_cast<SubRegion>(R); + + // Only subregions can have stack storage. + if (!SR) + return false; + MemSpaceRegion* S = getStackRegion(); - while (R) { - if (R == S) return true; - R = R->getSuperRegion(); + while (SR) { + R = SR->getSuperRegion(); + if (R == S) + return true; + + SR = dyn_cast<SubRegion>(R); } return false; diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index 6757f43ae1..48706ce805 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -52,7 +52,7 @@ public: Store RegionStoreManager::SetSVal(Store store, Loc LV, SVal V) { assert(LV.getSubKind() == loc::MemRegionKind); - MemRegion* R = cast<loc::MemRegionVal>(LV).getRegion(); + const MemRegion* R = cast<loc::MemRegionVal>(LV).getRegion(); if (!R) return store; |