From 222e2a7620e6520ffaf4fc4e69d79c18da31542e Mon Sep 17 00:00:00 2001 From: "Zancanaro; Carlo" Date: Mon, 24 Sep 2012 09:58:17 +1000 Subject: Add the clang library to the repo (with some of my changes, too). --- clang/test/Analysis/dynamic-cast.cpp | 230 +++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 clang/test/Analysis/dynamic-cast.cpp (limited to 'clang/test/Analysis/dynamic-cast.cpp') 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(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(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(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(pbb); + BB *s = dynamic_cast(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(pbb); + return b->m; // no warning +} + +int testLHS() { + B aa; + A *a = &aa; + return (dynamic_cast(a))->m; +} + +int testLHS2() { + B aa; + A *a = &aa; + return (*dynamic_cast(a)).m; +} + +int testDynCastUnknown2(class A *a) { + B *b = dynamic_cast(a); + return b->m; // no warning +} + +int testDynCastUnknown(class A *a) { + B *b = dynamic_cast(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(pa); + return b->m; // expected-warning {{dereference of a null pointer}} +} + +int testLHSFail() { + C c; + A *a = &c; + return (*dynamic_cast(a)).m; // expected-warning {{Dereference of null pointer}} +} + +int testBaseToDerivedFail() { + A a; + B *b = dynamic_cast(&a); + return b->m; // expected-warning {{dereference of a null pointer}} +} + +int testConstZeroFail() { + B *b = dynamic_cast((A *)0); + return b->m; // expected-warning {{dereference of a null pointer}} +} + +int testConstZeroFail2() { + A *a = 0; + B *b = dynamic_cast(a); + return b->m; // expected-warning {{dereference of a null pointer}} +} + +int testUpcast() { + B b; + A *a = dynamic_cast(&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(&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(rb); + int *x = 0; + return *x; // expected-warning {{Dereference of null pointer}} +} + +int testReferenceFailedCast() { + A a; + B &b = dynamic_cast(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(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(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(a); + return b->m; +} + -- cgit v1.2.3