summaryrefslogtreecommitdiff
path: root/clang/test/Analysis/dynamic-cast.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/test/Analysis/dynamic-cast.cpp')
-rw-r--r--clang/test/Analysis/dynamic-cast.cpp230
1 files changed, 230 insertions, 0 deletions
diff --git a/clang/test/Analysis/dynamic-cast.cpp b/clang/test/Analysis/dynamic-cast.cpp
new file mode 100644
index 0000000..8e63b2b
--- /dev/null
+++ b/clang/test/Analysis/dynamic-cast.cpp
@@ -0,0 +1,230 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core -verify %s
+
+class A {
+public:
+ virtual void f(){};
+
+};
+class B : public A{
+public:
+ int m;
+};
+class C : public A{};
+
+class BB: public B{};
+
+// A lot of the tests below have the if statement in them, which forces the
+// analyzer to explore both path - when the result is 0 and not. This makes
+// sure that we definitely know that the result is non-0 (as the result of
+// the cast).
+int testDynCastFromRadar() {
+ B aa;
+ A *a = &aa;
+ const int* res = 0;
+ B *b = dynamic_cast<B*>(a);
+ static const int i = 5;
+ if(b) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // no warning
+}
+
+int testBaseToBase1() {
+ B b;
+ B *pb = &b;
+ B *pbb = dynamic_cast<B*>(pb);
+ const int* res = 0;
+ static const int i = 5;
+ if (pbb) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // no warning
+}
+
+int testMultipleLevelsOfSubclassing1() {
+ BB bb;
+ B *pb = &bb;
+ A *pa = pb;
+ B *b = dynamic_cast<B*>(pa);
+ const int* res = 0;
+ static const int i = 5;
+ if (b) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // no warning
+}
+
+int testMultipleLevelsOfSubclassing2() {
+ BB bb;
+ A *pbb = &bb;
+ B *b = dynamic_cast<B*>(pbb);
+ BB *s = dynamic_cast<BB*>(b);
+ const int* res = 0;
+ static const int i = 5;
+ if (s) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // no warning
+}
+
+int testMultipleLevelsOfSubclassing3() {
+ BB bb;
+ A *pbb = &bb;
+ B *b = dynamic_cast<B*>(pbb);
+ return b->m; // no warning
+}
+
+int testLHS() {
+ B aa;
+ A *a = &aa;
+ return (dynamic_cast<B*>(a))->m;
+}
+
+int testLHS2() {
+ B aa;
+ A *a = &aa;
+ return (*dynamic_cast<B*>(a)).m;
+}
+
+int testDynCastUnknown2(class A *a) {
+ B *b = dynamic_cast<B*>(a);
+ return b->m; // no warning
+}
+
+int testDynCastUnknown(class A *a) {
+ B *b = dynamic_cast<B*>(a);
+ const int* res = 0;
+ static const int i = 5;
+ if (b) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // expected-warning {{Dereference of null pointer}}
+}
+
+int testDynCastFail2() {
+ C c;
+ A *pa = &c;
+ B *b = dynamic_cast<B*>(pa);
+ return b->m; // expected-warning {{dereference of a null pointer}}
+}
+
+int testLHSFail() {
+ C c;
+ A *a = &c;
+ return (*dynamic_cast<B*>(a)).m; // expected-warning {{Dereference of null pointer}}
+}
+
+int testBaseToDerivedFail() {
+ A a;
+ B *b = dynamic_cast<B*>(&a);
+ return b->m; // expected-warning {{dereference of a null pointer}}
+}
+
+int testConstZeroFail() {
+ B *b = dynamic_cast<B*>((A *)0);
+ return b->m; // expected-warning {{dereference of a null pointer}}
+}
+
+int testConstZeroFail2() {
+ A *a = 0;
+ B *b = dynamic_cast<B*>(a);
+ return b->m; // expected-warning {{dereference of a null pointer}}
+}
+
+int testUpcast() {
+ B b;
+ A *a = dynamic_cast<A*>(&b);
+ const int* res = 0;
+ static const int i = 5;
+ if (a) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // no warning
+}
+
+int testCastToVoidStar() {
+ A a;
+ void *b = dynamic_cast<void*>(&a);
+ const int* res = 0;
+ static const int i = 5;
+ if (b) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // no warning
+}
+
+int testReferenceSuccesfulCast() {
+ B rb;
+ B &b = dynamic_cast<B&>(rb);
+ int *x = 0;
+ return *x; // expected-warning {{Dereference of null pointer}}
+}
+
+int testReferenceFailedCast() {
+ A a;
+ B &b = dynamic_cast<B&>(a);
+ int *x = 0;
+ return *x; // no warning (An exception is thrown by the cast.)
+}
+
+// Here we allow any outcome of the cast and this is good because there is a
+// situation where this will fail. So if the user has written the code in this
+// way, we assume they expect the cast to succeed.
+// Note, this might need special handling if we track types of symbolic casts
+// and use them for dynamic_cast handling.
+int testDynCastMostLikelyWillFail(C *c) {
+ B *b = 0;
+ b = dynamic_cast<B*>(c);
+ const int* res = 0;
+ static const int i = 5;
+ if (b) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // expected-warning{{Dereference of null pointer}}
+}
+
+class M : public B, public C {};
+void callTestDynCastMostLikelyWillFail() {
+ M m;
+ testDynCastMostLikelyWillFail(&m);
+}
+
+// False positives/negatives.
+
+// Due to symbolic regions not being typed.
+int testDynCastFalsePositive(BB *c) {
+ B *b = 0;
+ b = dynamic_cast<B*>(c);
+ const int* res = 0;
+ static const int i = 5;
+ if (b) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // expected-warning{{Dereference of null pointer}}
+}
+
+// Does not work when we new an object.
+int testDynCastFail3() {
+ A *a = new A();
+ B *b = dynamic_cast<B*>(a);
+ return b->m;
+}
+