summaryrefslogtreecommitdiff
path: root/clang
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2018-09-26 00:17:14 +0000
committerArtem Dergachev <artem.dergachev@gmail.com>2018-09-26 00:17:14 +0000
commitbe64e466daf426143304a48b4b63ab66faed1731 (patch)
tree01b352ae1c52ab74403d96fb0e7034e4a2723855 /clang
parent5c3a854887dfbfcff063261b7990563f38edc61b (diff)
[analyzer] Fix a crash on casting symbolic pointers to derived classes.
Commit r340984 causes a crash when a pointer to a completely unrelated type UnrelatedT (eg., opaque struct pattern) is being casted from base class BaseT to derived class DerivedT, which results in an ill-formed region Derived{SymRegion{$<UnrelatedT x>}, DerivedT}. Differential Revision: https://reviews.llvm.org/D52189
Diffstat (limited to 'clang')
-rw-r--r--clang/lib/StaticAnalyzer/Core/Store.cpp12
-rw-r--r--clang/test/Analysis/casts.cpp30
2 files changed, 41 insertions, 1 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/Store.cpp b/clang/lib/StaticAnalyzer/Core/Store.cpp
index c3b706d90f6..cc9939a68dc 100644
--- a/clang/lib/StaticAnalyzer/Core/Store.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Store.cpp
@@ -375,8 +375,18 @@ SVal StoreManager::attemptDownCast(SVal Base, QualType TargetType,
MR = Uncasted;
}
+ // If we're casting a symbolic base pointer to a derived class, use
+ // CXXDerivedObjectRegion to represent the cast. If it's a pointer to an
+ // unrelated type, it must be a weird reinterpret_cast and we have to
+ // be fine with ElementRegion. TODO: Should we instead make
+ // Derived{TargetClass, Element{SourceClass, SR}}?
if (const auto *SR = dyn_cast<SymbolicRegion>(MR)) {
- return loc::MemRegionVal(MRMgr.getCXXDerivedObjectRegion(TargetClass, SR));
+ QualType T = SR->getSymbol()->getType();
+ const CXXRecordDecl *SourceClass = T->getPointeeCXXRecordDecl();
+ if (TargetClass && SourceClass && TargetClass->isDerivedFrom(SourceClass))
+ return loc::MemRegionVal(
+ MRMgr.getCXXDerivedObjectRegion(TargetClass, SR));
+ return loc::MemRegionVal(GetElementZeroRegion(SR, TargetType));
}
// We failed if the region we ended up with has perfect type info.
diff --git a/clang/test/Analysis/casts.cpp b/clang/test/Analysis/casts.cpp
index 9b3e294c779..2c291052793 100644
--- a/clang/test/Analysis/casts.cpp
+++ b/clang/test/Analysis/casts.cpp
@@ -70,5 +70,35 @@ void foo(B *b) {
clang_analyzer_eval(c->x); // expected-warning{{UNKNOWN}}
clang_analyzer_eval(c->y); // expected-warning{{TRUE}}
}
+} // namespace base_to_derived_double_inheritance
+
+namespace base_to_derived_opaque_class {
+class NotInt {
+public:
+ operator int() { return !x; } // no-crash
+ int x;
+};
+
+typedef struct Opaque *OpaqueRef;
+typedef void *VeryOpaqueRef;
+
+class Transparent {
+public:
+ int getNotInt() { return NI; }
+ NotInt NI;
+};
+
+class SubTransparent : public Transparent {};
+
+SubTransparent *castToDerived(Transparent *TRef) {
+ return (SubTransparent *)TRef;
}
+void foo(OpaqueRef ORef) {
+ castToDerived(reinterpret_cast<Transparent *>(ORef))->getNotInt();
+}
+
+void foo(VeryOpaqueRef ORef) {
+ castToDerived(reinterpret_cast<Transparent *>(ORef))->getNotInt();
+}
+} // namespace base_to_derived_opaque_class