aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2013-02-15 01:23:24 +0000
committerJordan Rose <jordan_rose@apple.com>2013-02-15 01:23:24 +0000
commitada0d224fcff5ff07c9dd846379592f92ccf5ee7 (patch)
treeefc98692534cbbf465a59cf1440ddef639b2e6e7
parentbc403861bc4e6f7ad1371e9e129f0f25b38b3a9a (diff)
[analyzer] Don't assert when mixing reinterpret_cast and derived-to-base casts.
This just adds a very simple check that if a DerivedToBase CastExpr is operating on a value with known C++ object type, and that type is not the base type specified in the AST, then the cast is invalid and we should return UnknownVal. In the future, perhaps we can have a checker that specifies that this is illegal, but we still shouldn't assert even if the user turns that checker off. PR14872 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175239 91177308-0d34-0410-b5e6-96231b3b80d8
-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);
+ }
+}