aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core/RegionStore.cpp
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-04-10 20:59:00 +0000
committerAnna Zaks <ganna@apple.com>2012-04-10 20:59:00 +0000
commite19f86edab8fb3c2c1e99e0e9815b6058504df9b (patch)
tree3e14d3f8e1a6d36ad4eb676d7f98bf79935a7e1e /lib/StaticAnalyzer/Core/RegionStore.cpp
parent4335a48214dcbb258e08c8867c45648e25edb2ec (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.cpp83
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.
//===----------------------------------------------------------------------===//