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
// 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;
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}}
+ }
+}