diff options
author | Jordan Rose <jordan_rose@apple.com> | 2012-09-07 01:19:42 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2012-09-07 01:19:42 +0000 |
commit | 8f0d0fef5f90b16600cdb802d5d7344417c34aad (patch) | |
tree | d237b393a9175b705813c37c3f474c54f5247656 | |
parent | 061707a86f20bf608758e7013df24bd1be12ffc6 (diff) |
[analyzer] Fail gracefully when the dynamic type is outside the hierarchy.
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
-rw-r--r-- | lib/StaticAnalyzer/Core/CallEvent.cpp | 10 | ||||
-rw-r--r-- | test/Analysis/inline.cpp | 32 |
2 files changed, 41 insertions, 1 deletions
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index 7d58e806a7..50d16f9728 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -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; diff --git a/test/Analysis/inline.cpp b/test/Analysis/inline.cpp index 573b1647a3..6491b12c58 100644 --- a/test/Analysis/inline.cpp +++ b/test/Analysis/inline.cpp @@ -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}} + } +} |