From 599f85ab85e7ec380b0bb866bfc23a87726423c8 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Thu, 21 Feb 2013 03:12:32 +0000 Subject: [PATCH] [analyzer] Record whether a base object region represents a virtual base. This allows MemRegion and MemRegionManager to avoid asking over and over again whether an class is a virtual base or a non-virtual base. Minor optimization/cleanup; no functionality change. llvm-svn: 175716 --- .../StaticAnalyzer/Core/PathSensitive/MemRegion.h | 26 +++--- .../StaticAnalyzer/Core/PathSensitive/Store.h | 3 +- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 6 +- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 6 +- clang/lib/StaticAnalyzer/Core/MemRegion.cpp | 92 ++++++++++++---------- clang/lib/StaticAnalyzer/Core/Store.cpp | 11 ++- 6 files changed, 84 insertions(+), 60 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index a72273f..eb59478 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -1055,16 +1055,18 @@ public: class CXXBaseObjectRegion : public TypedValueRegion { friend class MemRegionManager; - const CXXRecordDecl *decl; + llvm::PointerIntPair Data; - CXXBaseObjectRegion(const CXXRecordDecl *d, const MemRegion *sReg) - : TypedValueRegion(sReg, CXXBaseObjectRegionKind), decl(d) {} + CXXBaseObjectRegion(const CXXRecordDecl *RD, bool IsVirtual, + const MemRegion *SReg) + : TypedValueRegion(SReg, CXXBaseObjectRegionKind), Data(RD, IsVirtual) {} - static void ProfileRegion(llvm::FoldingSetNodeID &ID, - const CXXRecordDecl *decl, const MemRegion *sReg); + static void ProfileRegion(llvm::FoldingSetNodeID &ID, const CXXRecordDecl *RD, + bool IsVirtual, const MemRegion *SReg); public: - const CXXRecordDecl *getDecl() const { return decl; } + const CXXRecordDecl *getDecl() const { return Data.getPointer(); } + bool isVirtual() const { return Data.getInt(); } QualType getValueType() const; @@ -1214,15 +1216,21 @@ public: const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex, LocationContext const *LC); - const CXXBaseObjectRegion *getCXXBaseObjectRegion(const CXXRecordDecl *decl, - const MemRegion *superRegion); + /// Create a CXXBaseObjectRegion with the given base class for region + /// \p Super. + /// + /// The type of \p Super is assumed be a class deriving from \p BaseClass. + const CXXBaseObjectRegion * + getCXXBaseObjectRegion(const CXXRecordDecl *BaseClass, const MemRegion *Super, + bool IsVirtual); /// Create a CXXBaseObjectRegion with the same CXXRecordDecl but a different /// super region. const CXXBaseObjectRegion * getCXXBaseObjectRegionWithSuper(const CXXBaseObjectRegion *baseReg, const MemRegion *superRegion) { - return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion); + return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion, + baseReg->isVirtual()); } const FunctionTextRegion *getFunctionTextRegion(const NamedDecl *FD); diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index c515105..066cd20 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -136,7 +136,8 @@ public: SVal evalDerivedToBase(SVal Derived, const CXXBasePath &CastPath); /// Evaluates a derived-to-base cast through a single level of derivation. - SVal evalDerivedToBase(SVal Derived, QualType DerivedPtrType); + SVal evalDerivedToBase(SVal Derived, QualType DerivedPtrType, + bool IsVirtual); /// \brief Evaluates C++ dynamic_cast cast. /// The callback may result in the following 3 scenarios: diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 89df40f..d03f3bd 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -487,8 +487,10 @@ void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D, SVal ThisVal = Pred->getState()->getSVal(ThisPtr); // Create the base object region. - QualType BaseTy = D.getBaseSpecifier()->getType(); - SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy); + const CXXBaseSpecifier *Base = D.getBaseSpecifier(); + QualType BaseTy = Base->getType(); + SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy, + Base->isVirtual()); VisitCXXDestructor(BaseTy, BaseVal.castAs().getRegion(), CurDtor->getBody(), /*IsBase=*/ true, Pred, Dst); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index cb3339d..d7cb5d1 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -161,8 +161,10 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, Target = ThisVal.getAsRegion(); } else { // Cast to the base type. - QualType BaseTy = CE->getType(); - SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy); + bool IsVirtual = + (CE->getConstructionKind() == CXXConstructExpr::CK_VirtualBase); + SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, CE->getType(), + IsVirtual); Target = BaseVal.getAsRegion(); } break; diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp index 922a984..9792a30 100644 --- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -234,7 +234,7 @@ QualType ObjCIvarRegion::getValueType() const { } QualType CXXBaseObjectRegion::getValueType() const { - return QualType(decl->getTypeForDecl(), 0); + return QualType(getDecl()->getTypeForDecl(), 0); } //===----------------------------------------------------------------------===// @@ -402,14 +402,16 @@ void CXXTempObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const { } void CXXBaseObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, - const CXXRecordDecl *decl, - const MemRegion *sReg) { - ID.AddPointer(decl); - ID.AddPointer(sReg); + const CXXRecordDecl *RD, + bool IsVirtual, + const MemRegion *SReg) { + ID.AddPointer(RD); + ID.AddBoolean(IsVirtual); + ID.AddPointer(SReg); } void CXXBaseObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const { - ProfileRegion(ID, decl, superRegion); + ProfileRegion(ID, getDecl(), isVirtual(), superRegion); } //===----------------------------------------------------------------------===// @@ -472,7 +474,7 @@ void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const { } void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const { - os << "base{" << superRegion << ',' << decl->getName() << '}'; + os << "base{" << superRegion << ',' << getDecl()->getName() << '}'; } void CXXThisRegion::dumpToStream(raw_ostream &os) const { @@ -885,41 +887,49 @@ MemRegionManager::getCXXTempObjectRegion(Expr const *E, return getSubRegion(E, getStackLocalsRegion(SFC)); } -const CXXBaseObjectRegion * -MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *decl, - const MemRegion *superRegion) { - // Check that the base class is actually a direct base of this region. - if (const TypedValueRegion *TVR = dyn_cast(superRegion)) { - if (const CXXRecordDecl *Class = TVR->getValueType()->getAsCXXRecordDecl()){ - if (Class->isVirtuallyDerivedFrom(decl)) { - // Virtual base regions should not be layered, since the layout rules - // are different. - while (const CXXBaseObjectRegion *Base = - dyn_cast(superRegion)) { - superRegion = Base->getSuperRegion(); - } - assert(superRegion && !isa(superRegion)); +/// Checks whether \p BaseClass is a valid virtual or direct non-virtual base +/// class of the type of \p Super. +static bool isValidBaseClass(const CXXRecordDecl *BaseClass, + const TypedValueRegion *Super, + bool IsVirtual) { + const CXXRecordDecl *Class = Super->getValueType()->getAsCXXRecordDecl(); + if (!Class) + return true; - } else { - // Non-virtual bases should always be direct bases. -#ifndef NDEBUG - bool FoundBase = false; - for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(), - E = Class->bases_end(); - I != E; ++I) { - if (I->getType()->getAsCXXRecordDecl() == decl) { - FoundBase = true; - break; - } - } + if (IsVirtual) + return Class->isVirtuallyDerivedFrom(BaseClass); - assert(FoundBase && "Not a direct base class of this region"); -#endif + for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(), + E = Class->bases_end(); + I != E; ++I) { + if (I->getType()->getAsCXXRecordDecl()->getCanonicalDecl() == BaseClass) + return true; + } + + return false; +} + +const CXXBaseObjectRegion * +MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *RD, + const MemRegion *Super, + bool IsVirtual) { + RD = RD->getCanonicalDecl(); + + if (const TypedValueRegion *TVR = dyn_cast(Super)) { + assert(isValidBaseClass(RD, TVR, IsVirtual)); + + if (IsVirtual) { + // Virtual base regions should not be layered, since the layout rules + // are different. + while (const CXXBaseObjectRegion *Base = + dyn_cast(Super)) { + Super = Base->getSuperRegion(); } + assert(Super && !isa(Super)); } } - return getSubRegion(decl, superRegion); + return getSubRegion(RD, IsVirtual, Super); } const CXXThisRegion* @@ -1146,14 +1156,12 @@ RegionOffset MemRegion::getAsOffset() const { if (SymbolicOffsetBase) continue; - const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Child); - CharUnits BaseOffset; - const CXXRecordDecl *Base = BOR->getDecl(); - if (Child->isVirtuallyDerivedFrom(Base)) - BaseOffset = Layout.getVBaseClassOffset(Base); + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Child); + if (BOR->isVirtual()) + BaseOffset = Layout.getVBaseClassOffset(BOR->getDecl()); else - BaseOffset = Layout.getBaseClassOffset(Base); + BaseOffset = Layout.getBaseClassOffset(BOR->getDecl()); // The base offset is in chars, not in bits. Offset += BaseOffset.getQuantity() * getContext().getCharWidth(); diff --git a/clang/lib/StaticAnalyzer/Core/Store.cpp b/clang/lib/StaticAnalyzer/Core/Store.cpp index 3695cbc..a0c24fe 100644 --- a/clang/lib/StaticAnalyzer/Core/Store.cpp +++ b/clang/lib/StaticAnalyzer/Core/Store.cpp @@ -254,7 +254,7 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, const CastExpr *Cast) { for (CastExpr::path_const_iterator I = Cast->path_begin(), E = Cast->path_end(); I != E; ++I) { - Result = evalDerivedToBase(Result, (*I)->getType()); + Result = evalDerivedToBase(Result, (*I)->getType(), (*I)->isVirtual()); } return Result; } @@ -264,12 +264,14 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, const CXXBasePath &Path) { SVal Result = Derived; for (CXXBasePath::const_iterator I = Path.begin(), E = Path.end(); I != E; ++I) { - Result = evalDerivedToBase(Result, I->Base->getType()); + Result = evalDerivedToBase(Result, I->Base->getType(), + I->Base->isVirtual()); } return Result; } -SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType) { +SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType, + bool IsVirtual) { Optional DerivedRegVal = Derived.getAs(); if (!DerivedRegVal) @@ -281,7 +283,8 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType) { assert(BaseDecl && "not a C++ object?"); const MemRegion *BaseReg = - MRMgr.getCXXBaseObjectRegion(BaseDecl, DerivedRegVal->getRegion()); + MRMgr.getCXXBaseObjectRegion(BaseDecl, DerivedRegVal->getRegion(), + IsVirtual); return loc::MemRegionVal(BaseReg); } -- 2.7.4