diff options
-rw-r--r-- | lib/StaticAnalyzer/Core/Store.cpp | 25 | ||||
-rw-r--r-- | test/Analysis/reinterpret-cast.cpp | 28 |
2 files changed, 53 insertions, 0 deletions
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp index e7e80dd01e..128dce4988 100644 --- a/lib/StaticAnalyzer/Core/Store.cpp +++ b/lib/StaticAnalyzer/Core/Store.cpp @@ -223,7 +223,32 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy) llvm_unreachable("unreachable"); } +static bool regionMatchesCXXRecordType(SVal V, QualType Ty) { + const MemRegion *MR = V.getAsRegion(); + if (!MR) + return true; + + const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(MR); + if (!TVR) + return true; + + const CXXRecordDecl *RD = TVR->getValueType()->getAsCXXRecordDecl(); + if (!RD) + return true; + + const CXXRecordDecl *Expected = Ty->getPointeeCXXRecordDecl(); + if (!Expected) + Expected = Ty->getAsCXXRecordDecl(); + + return Expected->getCanonicalDecl() == RD->getCanonicalDecl(); +} + SVal StoreManager::evalDerivedToBase(SVal Derived, const CastExpr *Cast) { + // Sanity check to avoid doing the wrong thing in the face of + // reinterpret_cast. + if (!regionMatchesCXXRecordType(Derived, Cast->getSubExpr()->getType())) + return UnknownVal(); + // Walk through the cast path to create nested CXXBaseRegions. SVal Result = Derived; for (CastExpr::path_const_iterator I = Cast->path_begin(), diff --git a/test/Analysis/reinterpret-cast.cpp b/test/Analysis/reinterpret-cast.cpp index e82f7b6869..aaa600e4b9 100644 --- a/test/Analysis/reinterpret-cast.cpp +++ b/test/Analysis/reinterpret-cast.cpp @@ -18,3 +18,31 @@ void test(Data data) { wrapper->set(); clang_analyzer_eval(wrapper->x == 42); // expected-warning{{TRUE}} } + +namespace PR14872 { + class Base1 {}; + class Derived1 : public Base1 {}; + + Derived1 *f1(); + + class Base2 {}; + class Derived2 : public Base2 {}; + + void f2(Base2 *foo); + + void f3(void** out) + { + Base1 *v; + v = f1(); + *out = v; + } + + void test() + { + Derived2 *p; + f3(reinterpret_cast<void**>(&p)); + // Don't crash when upcasting here. + // In this case, 'p' actually refers to a Derived1. + f2(p); + } +} |