aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp25
-rw-r--r--test/Analysis/reinterpret-cast.cpp28
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);
+ }
+}