From: Ted Kremenek Date: Tue, 5 Jan 2010 02:18:06 +0000 (+0000) Subject: Make static analysis support for C++ 'this' expression context-sensitive. Essentiall... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=de0d26310191215a6d1d189dc419f87af18ce6be;p=clang Make static analysis support for C++ 'this' expression context-sensitive. Essentially treat 'this' as a implicit parameter to the method call, and associate a region with it. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@92675 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h index b57cfd7b52..99aa3e15d7 100644 --- a/include/clang/Analysis/PathSensitive/MemRegion.h +++ b/include/clang/Analysis/PathSensitive/MemRegion.h @@ -65,6 +65,7 @@ public: BlockTextRegionKind, BlockDataRegionKind, CompoundLiteralRegionKind, + CXXThisRegionKind, StringRegionKind, ElementRegionKind, // Decl Regions. @@ -99,17 +100,13 @@ public: const MemRegion *StripCasts() const; - bool hasStackStorage() const; - - bool hasParametersStorage() const; - - bool hasGlobalsStorage() const; - bool hasGlobalsOrParametersStorage() const; - bool hasHeapStorage() const; - - bool hasHeapOrStackStorage() const; + bool hasStackStorage() const; + + bool hasStackNonParametersStorage() const; + + bool hasStackParametersStorage() const; virtual void dumpToStream(llvm::raw_ostream& os) const; @@ -634,6 +631,36 @@ public: return R->getKind() == VarRegionKind; } }; + +/// CXXThisRegion - Represents the region for the implicit 'this' parameter +/// in a call to a C++ method. This region doesn't represent the object +/// referred to by 'this', but rather 'this' itself. +class CXXThisRegion : public TypedRegion { + friend class MemRegionManager; + CXXThisRegion(const PointerType *thisPointerTy, + const MemRegion *sReg) + : TypedRegion(sReg, CXXThisRegionKind), ThisPointerTy(thisPointerTy) {} + + static void ProfileRegion(llvm::FoldingSetNodeID &ID, + const PointerType *PT, + const MemRegion *sReg); + + void Profile(llvm::FoldingSetNodeID &ID) const; + +public: + QualType getValueType(ASTContext &C) const { + return QualType(ThisPointerTy, 0); + } + + void dumpToStream(llvm::raw_ostream& os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == CXXThisRegionKind; + } + +private: + const PointerType *ThisPointerTy; +}; class FieldRegion : public DeclRegion { friend class MemRegionManager; @@ -824,6 +851,11 @@ public: const CompoundLiteralRegion* getCompoundLiteralRegion(const CompoundLiteralExpr* CL, const LocationContext *LC); + + /// getCXXThisRegion - Retrieve the [artifical] region associated with the + /// parameter 'this'. + const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy, + const LocationContext *LC); /// getSymbolicRegion - Retrieve or create a "symbolic" memory region. const SymbolicRegion* getSymbolicRegion(SymbolRef sym); diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Analysis/PathSensitive/Store.h index 52d73da15b..aaf8223b66 100644 --- a/include/clang/Analysis/PathSensitive/Store.h +++ b/include/clang/Analysis/PathSensitive/Store.h @@ -103,9 +103,6 @@ public: virtual SVal getLValueElement(QualType elementType, SVal offset, SVal Base)=0; - // T - the object type. - Loc getThisObject(QualType T); - // FIXME: Make out-of-line. virtual DefinedOrUnknownSVal getSizeInElements(const GRState *state, const MemRegion *region) { diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 013bed04f9..3c2512215a 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -2711,8 +2711,13 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, ExplodedNodeSet & Dst) { // Get the this object region from StoreManager. - Loc V = getStoreManager().getThisObject(TE->getType()->getPointeeType()); - MakeNode(Dst, TE, Pred, GetState(Pred)->BindExpr(TE, V)); + const MemRegion *R = + ValMgr.getRegionManager().getCXXThisRegion(TE->getType(), + Pred->getLocationContext()); + + const GRState *state = GetState(Pred); + SVal V = state->getSVal(loc::MemRegionVal(R)); + MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); } void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp index 74fe3bf5ee..5be882ad54 100644 --- a/lib/Analysis/MemRegion.cpp +++ b/lib/Analysis/MemRegion.cpp @@ -215,6 +215,18 @@ void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, ID.AddPointer(superRegion); } +void CXXThisRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, + const PointerType *PT, + const MemRegion *sRegion) { + ID.AddInteger((unsigned) CXXThisRegionKind); + ID.AddPointer(PT); + ID.AddPointer(sRegion); +} + +void CXXThisRegion::Profile(llvm::FoldingSetNodeID &ID) const { + CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion); +} + void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D, const MemRegion* superRegion, Kind k) { ID.AddInteger((unsigned) k); @@ -343,6 +355,10 @@ void CompoundLiteralRegion::dumpToStream(llvm::raw_ostream& os) const { os << "{ " << (void*) CL << " }"; } +void CXXThisRegion::dumpToStream(llvm::raw_ostream &os) const { + os << "this"; +} + void ElementRegion::dumpToStream(llvm::raw_ostream& os) const { os << "element{" << superRegion << ',' << Index << ',' << getElementType().getAsString() << '}'; @@ -551,7 +567,7 @@ const SymbolicRegion *MemRegionManager::getSymbolicRegion(SymbolRef sym) { return getSubRegion(sym, getUnknownRegion()); } -const FieldRegion * +const FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl* d, const MemRegion* superRegion){ return getSubRegion(d, superRegion); @@ -563,11 +579,21 @@ MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d, return getSubRegion(d, superRegion); } -const CXXObjectRegion * +const CXXObjectRegion* MemRegionManager::getCXXObjectRegion(QualType T) { return getSubRegion(T, getUnknownRegion()); } +const CXXThisRegion* +MemRegionManager::getCXXThisRegion(QualType thisPointerTy, + const LocationContext *LC) { + const StackFrameContext *STC = LC->getCurrentStackFrame(); + assert(STC); + const PointerType *PT = thisPointerTy->getAs(); + assert(PT); + return getSubRegion(PT, getStackArgumentsRegion(STC)); +} + const AllocaRegion* MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt, const LocationContext *LC) { @@ -592,20 +618,11 @@ bool MemRegion::hasStackStorage() const { return isa(getMemorySpace()); } -bool MemRegion::hasHeapStorage() const { - return isa(getMemorySpace()); -} - -bool MemRegion::hasHeapOrStackStorage() const { - const MemSpaceRegion *MS = getMemorySpace(); - return isa(MS) || isa(MS); -} - -bool MemRegion::hasGlobalsStorage() const { - return isa(getMemorySpace()); +bool MemRegion::hasStackNonParametersStorage() const { + return isa(getMemorySpace()); } -bool MemRegion::hasParametersStorage() const { +bool MemRegion::hasStackParametersStorage() const { return isa(getMemorySpace()); } diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index 3bc9dccda6..ba63308c5d 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -28,7 +28,6 @@ using namespace clang; -#define HEAP_UNDEFINED 0 #define USE_EXPLICIT_COMPOUND 0 namespace { @@ -723,6 +722,8 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, const MemRegion *R) { switch (R->getKind()) { + case MemRegion::CXXThisRegionKind: + assert(0 && "Cannot get size of 'this' region"); case MemRegion::GenericMemSpaceRegionKind: case MemRegion::StackLocalsSpaceRegionKind: case MemRegion::StackArgumentsSpaceRegionKind: @@ -877,6 +878,9 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state, // Technically this can happen if people do funny things with casts. return UnknownVal(); + case MemRegion::CXXThisRegionKind: + assert(0 && + "Cannot perform pointer arithmetic on implicit argument 'this'"); case MemRegion::GenericMemSpaceRegionKind: case MemRegion::StackLocalsSpaceRegionKind: case MemRegion::StackArgumentsSpaceRegionKind: @@ -1076,12 +1080,7 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { // The location does not have a bound value. This means that it has // the value it had upon its creation and/or entry to the analyzed // function/method. These are either symbolic values or 'undefined'. - -#if HEAP_UNDEFINED - if (R->hasHeapOrStackStorage()) { -#else - if (R->hasStackStorage()) { -#endif + if (R->hasStackNonParametersStorage()) { // All stack variables are considered to have undefined values // upon creation. All heap allocated blocks are considered to // have undefined values as well unless they are explicitly bound @@ -1240,8 +1239,7 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state, cast(lazyBindingRegion)); } - if (R->hasStackStorage() && !R->hasParametersStorage()) { - + if (R->hasStackNonParametersStorage()) { if (isa(R)) { // Currently we don't reason specially about Clang-style vectors. Check // if superR is a vector and if so return Unknown. diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp index 8d911b844f..4d15023001 100644 --- a/lib/Analysis/Store.cpp +++ b/lib/Analysis/Store.cpp @@ -77,6 +77,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) // Process region cast according to the kind of the region being cast. switch (R->getKind()) { + case MemRegion::CXXThisRegionKind: case MemRegion::GenericMemSpaceRegionKind: case MemRegion::StackLocalsSpaceRegionKind: case MemRegion::StackArgumentsSpaceRegionKind: @@ -240,8 +241,3 @@ SVal StoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL, const LocationContext *LC) { return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)); } - -Loc StoreManager::getThisObject(QualType T) { - const CXXObjectRegion *R = MRMgr.getCXXObjectRegion(T); - return loc::MemRegionVal(R); -} diff --git a/test/Analysis/misc-ps-region-store.cpp b/test/Analysis/misc-ps-region-store.cpp index 225abb5aa1..8b58131187 100644 --- a/test/Analysis/misc-ps-region-store.cpp +++ b/test/Analysis/misc-ps-region-store.cpp @@ -34,6 +34,10 @@ int test3(Test3_Derived x) { return test3_aux(x); } +//===---------------------------------------------------------------------===// +// Test CFG support for C++ condition variables. +//===---------------------------------------------------------------------===// + int test_init_in_condition_aux(); int test_init_in_condition() { if (int x = test_init_in_condition_aux()) { // no-warning @@ -89,3 +93,42 @@ int test_init_in_condition_for() { *p = 0xDEADBEEF; // no-warning return 0; } + +//===---------------------------------------------------------------------===// +// Test handling of 'this' pointer. +//===---------------------------------------------------------------------===// + +class TestHandleThis { + int x; + + TestHandleThis(); + int foo(); + int null_deref_negative(); + int null_deref_positive(); +}; + +int TestHandleThis::foo() { + // Assume that 'x' is initialized. + return x + 1; // no-warning +} + +int TestHandleThis::null_deref_negative() { + x = 10; + if (x == 10) { + return 1; + } + int *p = 0; + *p = 0xDEADBEEF; // no-warning + return 0; +} + +int TestHandleThis::null_deref_positive() { + x = 10; + if (x == 9) { + return 1; + } + int *p = 0; + *p = 0xDEADBEEF; // expected-warning{{null pointer}} + return 0; +} +