]> granicus.if.org Git - clang/commitdiff
[analyzer] Fail gracefully when the dynamic type is outside the hierarchy.
authorJordan Rose <jordan_rose@apple.com>
Fri, 7 Sep 2012 01:19:42 +0000 (01:19 +0000)
committerJordan Rose <jordan_rose@apple.com>
Fri, 7 Sep 2012 01:19:42 +0000 (01:19 +0000)
With some particularly evil casts, we can get an object whose dynamic type
is not actually a subclass of its static type. In this case, we won't even
find the statically-resolved method as a devirtualization candidate.

Rather than assert that this situation cannot occur, we now simply check
that the dynamic type is not an ancestor or descendent of the static type,
and leave it at that.

This error actually occurred analyzing LLVM: CallEventManager uses a
BumpPtrAllocator to allocate a concrete subclass of CallEvent
(FunctionCall), but then casts it to the actual subclass requested
(such as ObjCMethodCall) to perform the constructor.

Yet another crash in PR13763.

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

lib/StaticAnalyzer/Core/CallEvent.cpp
test/Analysis/inline.cpp

index 7d58e806a73cccc710ca15a27010ad905a70e04e..50d16f97283291bb90812d5c2e621b00a20af897 100644 (file)
@@ -435,7 +435,15 @@ RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const {
 
   // Find the decl for this method in that class.
   const CXXMethodDecl *Result = MD->getCorrespondingMethodInClass(RD, true);
-  assert(Result && "At the very least the static decl should show up.");
+  if (!Result) {
+    // We might not even get the original statically-resolved method due to
+    // some particularly nasty casting (e.g. casts to sister classes).
+    // However, we should at least be able to search up and down our own class
+    // hierarchy, and some real bugs have been caught by checking this.
+    assert(!MD->getParent()->isDerivedFrom(RD) && "Bad DynamicTypeInfo");
+    assert(!RD->isDerivedFrom(MD->getParent()) && "Couldn't find known method");
+    return RuntimeDefinition();
+  }
 
   // Does the decl that we found have an implementation?
   const FunctionDecl *Definition;
index 573b1647a33385e4f1ee1d88161c765c868691c8..6491b12c5851cffb798f9689d209047b9decd948 100644 (file)
@@ -267,3 +267,35 @@ namespace OperatorNew {
     clang_analyzer_eval(obj->value == 42); // expected-warning{{UNKNOWN}}
   }
 }
+
+
+namespace VirtualWithSisterCasts {
+  struct Parent {
+    virtual int foo();
+  };
+
+  struct A : Parent {
+    virtual int foo() { return 42; }
+  };
+
+  struct B : Parent {
+    virtual int foo();
+  };
+
+  struct Unrelated {};
+
+  void testDowncast(Parent *b) {
+    A *a = (A *)(void *)b;
+    clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}}
+  }
+
+  void testRelated(B *b) {
+    A *a = (A *)(void *)b;
+    clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}}
+  }
+
+  void testUnrelated(Unrelated *b) {
+    A *a = (A *)(void *)b;
+    clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}}
+  }
+}