]> granicus.if.org Git - clang/commitdiff
[analyzer] Fix a crash on casting symbolic pointers to derived classes.
authorArtem Dergachev <artem.dergachev@gmail.com>
Wed, 26 Sep 2018 00:17:14 +0000 (00:17 +0000)
committerArtem Dergachev <artem.dergachev@gmail.com>
Wed, 26 Sep 2018 00:17:14 +0000 (00:17 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@343051 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Core/Store.cpp
test/Analysis/casts.cpp

index c3b706d90f6496b093a4d465260b434d37383518..cc9939a68dc26aac846b7306fe8f4b8ba057d03f 100644 (file)
@@ -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.
index 9b3e294c7792f52235de41f6a115dcadbf8ba3a5..2c2910527932537af1d62a895df05485dd68bb4f 100644 (file)
@@ -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