diff options
author | Anna Zaks <ganna@apple.com> | 2012-04-10 20:59:00 +0000 |
---|---|---|
committer | Anna Zaks <ganna@apple.com> | 2012-04-10 20:59:00 +0000 |
commit | e19f86edab8fb3c2c1e99e0e9815b6058504df9b (patch) | |
tree | 3e14d3f8e1a6d36ad4eb676d7f98bf79935a7e1e /lib/StaticAnalyzer/Core/RegionStore.cpp | |
parent | 4335a48214dcbb258e08c8867c45648e25edb2ec (diff) |
[analyzer] Add support for C++ dynamic_cast.
Simulate the C++ dynamic_cast in the analyzer.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154434 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core/RegionStore.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/RegionStore.cpp | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp index 1619e6bc64..8fb7e88b38 100644 --- a/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -229,6 +229,16 @@ public: /// For DerivedToBase casts, create a CXXBaseObjectRegion and return it. virtual SVal evalDerivedToBase(SVal derived, QualType basePtrType); + /// \brief Evaluates C++ dynamic_cast cast. + /// The callback may result in the following 3 scenarios: + /// - Successful cast (ex: derived is subclass of base). + /// - Failed cast (ex: derived is definitely not a subclass of base). + /// - We don't know (base is a symbolic region and we don't have + /// enough info to determine if the cast will succeed at run time). + /// The function returns an SVal representing the derived class; it's + /// valid only if Failed flag is set to false. + virtual SVal evalDynamicCast(SVal base, QualType derivedPtrType,bool &Failed); + StoreRef getInitialStore(const LocationContext *InitLoc) { return StoreRef(RBFactory.getEmptyMap().getRootWithoutRetain(), *this); } @@ -877,6 +887,79 @@ SVal RegionStoreManager::evalDerivedToBase(SVal derived, QualType baseType) { return loc::MemRegionVal(baseReg); } +SVal RegionStoreManager::evalDynamicCast(SVal base, QualType derivedType, + bool &Failed) { + Failed = false; + + loc::MemRegionVal *baseRegVal = dyn_cast<loc::MemRegionVal>(&base); + if (!baseRegVal) + return UnknownVal(); + const MemRegion *BaseRegion = baseRegVal->stripCasts(); + + // Assume the derived class is a pointer to a CXX record. + // TODO: Note, we do not model reference types: a bad_cast exception is thrown + // when a cast of reference fails, but we just return an UnknownVal. + if (!derivedType->isPointerType()) + return UnknownVal(); + derivedType = derivedType->getPointeeType(); + assert(!derivedType.isNull()); + const CXXRecordDecl *DerivedDecl = derivedType->getAsCXXRecordDecl(); + if (!DerivedDecl && !derivedType->isVoidType()) + return UnknownVal(); + + // Drill down the CXXBaseObject chains, which represent upcasts (casts from + // derived to base). + const MemRegion *SR = BaseRegion; + while (const TypedRegion *TSR = dyn_cast_or_null<TypedRegion>(SR)) { + QualType BaseType = TSR->getLocationType()->getPointeeType(); + assert(!BaseType.isNull()); + const CXXRecordDecl *SRDecl = BaseType->getAsCXXRecordDecl(); + if (!SRDecl) + return UnknownVal(); + + // If found the derived class, the cast succeeds. + if (SRDecl == DerivedDecl) + return loc::MemRegionVal(TSR); + + // If the region type is a subclass of the derived type. + if (!derivedType->isVoidType() && SRDecl->isDerivedFrom(DerivedDecl)) { + // This occurs in two cases. + // 1) We are processing an upcast. + // 2) We are processing a downcast but we jumped directly from the + // ancestor to a child of the cast value, so conjure the + // appropriate region to represent value (the intermediate node). + return loc::MemRegionVal(MRMgr.getCXXBaseObjectRegion(DerivedDecl, + BaseRegion)); + } + + // If super region is not a parent of derived class, the cast definitely + // fails. + if (!derivedType->isVoidType() && + DerivedDecl->isProvablyNotDerivedFrom(SRDecl)) { + Failed = true; + return UnknownVal(); + } + + if (const CXXBaseObjectRegion *R = dyn_cast<CXXBaseObjectRegion>(TSR)) + // Drill down the chain to get the derived classes. + SR = R->getSuperRegion(); + else { + // We reached the bottom of the hierarchy. + + // If this is a cast to void*, return the region. + if (derivedType->isVoidType()) + return loc::MemRegionVal(TSR); + + // We did not find the derived class. We we must be casting the base to + // derived, so the cast should fail. + Failed = true; + return UnknownVal(); + } + } + + return UnknownVal(); +} + //===----------------------------------------------------------------------===// // Loading values from regions. //===----------------------------------------------------------------------===// |