From: Zhongxing Xu Date: Sun, 16 Nov 2008 04:07:26 +0000 (+0000) Subject: Enhances SCA to process untyped region to typed region conversion. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dc0a25d9bff956cdbe54ea0bfc8fbbe3ceb4eb92;p=clang Enhances SCA to process untyped region to typed region conversion. - RegionView and RegionViewMap is introduced to assist back-mapping from super region to subregions. - GDM is used to carry RegionView information. - AnonTypedRegion is added to represent a typed region introduced by pointer casting. Later AnonTypedRegion can be used in other similar cases, e.g., malloc()'ed region. - The specific conversion is delegated to store manager. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59382 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h index 04d904623e..287dd09c2b 100644 --- a/include/clang/Analysis/PathSensitive/MemRegion.h +++ b/include/clang/Analysis/PathSensitive/MemRegion.h @@ -23,6 +23,8 @@ #include "clang/AST/ASTContext.h" #include "llvm/Support/Casting.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableList.h" +#include "llvm/ADT/ImmutableMap.h" #include "llvm/Support/Allocator.h" #include @@ -42,12 +44,13 @@ public: BEG_TYPED_REGIONS, CompoundLiteralRegionKind, StringRegionKind, ElementRegionKind, + AnonTypedRegionKind, + AnonPointeeRegionKind, // Decl Regions. BEG_DECL_REGIONS, VarRegionKind, FieldRegionKind, ObjCIvarRegionKind, ObjCObjectRegionKind, END_DECL_REGIONS, - AnonPointeeRegionKind, END_TYPED_REGIONS }; private: const Kind kind; @@ -201,6 +204,32 @@ public: } }; +class AnonTypedRegion : public TypedRegion { + friend class MemRegionManager; + + QualType T; + + AnonTypedRegion(QualType t, const MemRegion* sreg) + : TypedRegion(sreg, AnonTypedRegionKind), T(t) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType T, + const MemRegion* superRegion); + +public: + + QualType getType(ASTContext& C) const { + return T; + } + + void Profile(llvm::FoldingSetNodeID& ID) const { + ProfileRegion(ID, T, superRegion); + } + + static bool classof(const MemRegion* R) { + return R->getKind() == AnonTypedRegionKind; + } +}; + /// AnonPointeeRegion - anonymous regions pointed-to by pointer function /// parameters or pointer globals. In RegionStoreManager, we assume pointer /// parameters or globals point at some anonymous region. Such regions are not @@ -494,7 +523,7 @@ class MemRegionManager { MemSpaceRegion* stack; MemSpaceRegion* heap; MemSpaceRegion* unknown; - + public: MemRegionManager(llvm::BumpPtrAllocator& a) : A(a), globals(0), stack(0), heap(0) {} @@ -559,10 +588,12 @@ public: ObjCIvarRegion* getObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* superRegion); + AnonTypedRegion* getAnonTypedRegion(QualType t, const MemRegion* superRegion); + AnonPointeeRegion* getAnonPointeeRegion(const VarDecl* d); bool hasStackStorage(const MemRegion* R); - + private: MemSpaceRegion* LazyAllocate(MemSpaceRegion*& region); }; diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Analysis/PathSensitive/Store.h index 5ec732fda8..06c49cb85c 100644 --- a/include/clang/Analysis/PathSensitive/Store.h +++ b/include/clang/Analysis/PathSensitive/Store.h @@ -80,6 +80,9 @@ public: /// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit /// conversions between arrays and pointers. virtual SVal ArrayToPointer(SVal Array) = 0; + + virtual const GRState* CastRegion(const GRState* St, SVal VoidPtr, + QualType CastToTy, Stmt* CastE) = 0; /// getSelfRegion - Returns the region for the 'self' (Objective-C) or /// 'this' object (C++). When used when analyzing a normal function this diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp index 4197c08a9c..8b5ef6ee86 100644 --- a/lib/Analysis/BasicStore.cpp +++ b/lib/Analysis/BasicStore.cpp @@ -65,6 +65,12 @@ public: /// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit /// conversions between arrays and pointers. SVal ArrayToPointer(SVal Array) { return Array; } + + const GRState* CastRegion(const GRState* St, SVal VoidPtr, QualType CastToTy, + Stmt* CastE) { + return St; + } + /// getSelfRegion - Returns the region for the 'self' (Objective-C) or /// 'this' object (C++). When used when analyzing a normal function this diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 55fbf1874a..e002c13637 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -1692,6 +1692,21 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst){ continue; } + // Check for casts from AllocaRegion pointer to typed pointer. + if (isa(V)) { + assert(Loc::IsLocType(T)); + assert(Loc::IsLocType(ExTy)); + + // Delegate to store manager. + const GRState* NewSt = getStoreManager().CastRegion(St, V, T, CastE); + + // If no new region is created, fall through to the default case. + if (NewSt != St) { + MakeNode(Dst, CastE, N, NewSt); + continue; + } + } + // All other cases. MakeNode(Dst, CastE, N, BindExpr(St, CastE, EvalCast(V, CastE->getType()))); } diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp index a292d98e60..4636eaef11 100644 --- a/lib/Analysis/MemRegion.cpp +++ b/lib/Analysis/MemRegion.cpp @@ -44,6 +44,13 @@ void AllocaRegion::Profile(llvm::FoldingSetNodeID& ID) const { ProfileRegion(ID, Ex, Cnt); } +void AnonTypedRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, QualType T, + const MemRegion* superRegion) { + ID.AddInteger((unsigned) AnonTypedRegionKind); + ID.Add(T); + ID.AddPointer(superRegion); +} + QualType AnonPointeeRegion::getType(ASTContext& C) const { QualType T = C.getCanonicalType(Pointer->getType()); PointerType* PTy = cast(T.getTypePtr()); @@ -110,7 +117,7 @@ QualType ElementRegion::getType(ASTContext& C) const { ArrayType* AT = cast(T.getTypePtr()); return AT->getElementType(); } - else if (isa(superRegion)) { + else if (isa(superRegion)) { PointerType* PtrT = cast(T.getTypePtr()); QualType PTy = PtrT->getPointeeType(); return C.getCanonicalType(PTy); @@ -369,6 +376,23 @@ MemRegionManager::getObjCObjectRegion(const ObjCInterfaceDecl* d, return R; } +AnonTypedRegion* +MemRegionManager::getAnonTypedRegion(QualType t, const MemRegion* superRegion) { + llvm::FoldingSetNodeID ID; + AnonTypedRegion::ProfileRegion(ID, t, superRegion); + + void* InsertPos; + MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos); + AnonTypedRegion* R = cast_or_null(data); + + if (!R) { + R = (AnonTypedRegion*) A.Allocate(); + new (R) AnonTypedRegion(t, superRegion); + Regions.InsertNode(R, InsertPos); + } + + return R; +} AnonPointeeRegion* MemRegionManager::getAnonPointeeRegion(const VarDecl* d) { llvm::FoldingSetNodeID ID; diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index f1c57b33bd..732785c0f7 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -16,26 +16,46 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/PathSensitive/MemRegion.h" #include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Analysis/PathSensitive/GRStateTrait.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/ImmutableList.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Compiler.h" using namespace clang; typedef llvm::ImmutableMap RegionBindingsTy; +typedef llvm::ImmutableList RegionViewTy; +typedef llvm::ImmutableMap RegionViewMapTy; + +static int RegionViewMapTyIndex = 0; + +namespace clang { +template<> struct GRStateTrait + : public GRStatePartialTrait { + static void* GDMIndex() { return &RegionViewMapTyIndex; } +}; +} namespace { class VISIBILITY_HIDDEN RegionStoreManager : public StoreManager { RegionBindingsTy::Factory RBFactory; + RegionViewTy::Factory RVFactory; + RegionViewMapTy::Factory RVMFactory; + GRStateManager& StateMgr; MemRegionManager MRMgr; public: RegionStoreManager(GRStateManager& mgr) - : StateMgr(mgr), MRMgr(StateMgr.getAllocator()) {} + : RBFactory(mgr.getAllocator()), + RVFactory(mgr.getAllocator()), + RVMFactory(mgr.getAllocator()), + StateMgr(mgr), + MRMgr(StateMgr.getAllocator()) {} virtual ~RegionStoreManager() {} @@ -62,6 +82,9 @@ public: SVal ArrayToPointer(SVal Array); + const GRState* CastRegion(const GRState* St, SVal VoidPtr, + QualType CastToTy, Stmt* CastE); + SVal Retrieve(Store S, Loc L, QualType T = QualType()); Store Bind(Store St, Loc LV, SVal V); @@ -112,6 +135,9 @@ private: // Utility methods. BasicValueFactory& getBasicVals() { return StateMgr.getBasicVals(); } ASTContext& getContext() { return StateMgr.getContext(); } + + const GRState* AddRegionView(const GRState* St, + const MemRegion* View, const MemRegion* Base); }; } // end anonymous namespace @@ -238,6 +264,30 @@ SVal RegionStoreManager::ArrayToPointer(SVal Array) { return loc::MemRegionVal(ER); } +const GRState* RegionStoreManager::CastRegion(const GRState* St, + SVal VoidPtr, + QualType CastToTy, + Stmt* CastE) { + if (const AllocaRegion* AR = + dyn_cast(cast(VoidPtr).getRegion())) { + + // Create a new region to attach type information to it. + const AnonTypedRegion* TR = MRMgr.getAnonTypedRegion(CastToTy, AR); + + // Get the pointer to the first element. + nonloc::ConcreteInt Idx(getBasicVals().getZeroWithPtrWidth(false)); + const ElementRegion* ER = MRMgr.getElementRegion(Idx, TR); + + St = StateMgr.BindExpr(St, CastE, loc::MemRegionVal(ER)); + + // Add a RegionView to base region. + return AddRegionView(St, TR, AR); + } + + // Default case. + return St; +} + SVal RegionStoreManager::Retrieve(Store S, Loc L, QualType T) { assert(!isa(L) && "location unknown"); assert(!isa(L) && "location undefined"); @@ -600,3 +650,19 @@ Store RegionStoreManager::BindStructToVal(Store store, const TypedRegion* BaseR, return store; } + +const GRState* RegionStoreManager::AddRegionView(const GRState* St, + const MemRegion* View, + const MemRegion* Base) { + GRStateRef state(St, StateMgr); + + // First, retrieve the region view of the base region. + RegionViewMapTy::data_type* d = state.get(Base); + RegionViewTy L = d ? *d : RVFactory.GetEmptyList(); + + // Now add View to the region view. + L = RVFactory.Add(View, L); + + // Create a new state with the new region view. + return state.set(Base, L); +}