dynamic-cast.cpp revision bfa9ab8183e2fdc74f8633d758cb0c6201314320
1// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=none -verify %s
2
3void clang_analyzer_eval(bool);
4
5class A {
6public:
7    virtual void f(){};
8
9};
10class B : public A{
11public:
12  int m;
13};
14class C : public A{};
15
16class BB: public B{};
17
18// A lot of the tests below have the if statement in them, which forces the
19// analyzer to explore both path - when the result is 0 and not. This makes
20// sure that we definitely know that the result is non-0 (as the result of
21// the cast).
22int testDynCastFromRadar() {
23    B aa;
24    A *a = &aa;
25    const int* res = 0;
26    B *b = dynamic_cast<B*>(a);
27    static const int i = 5;
28    if(b) {
29        res = &i;
30    } else {
31        res = 0;
32    }
33    return *res; // no warning
34}
35
36int testBaseToBase1() {
37  B b;
38  B *pb = &b;
39  B *pbb = dynamic_cast<B*>(pb);
40  const int* res = 0;
41  static const int i = 5;
42  if (pbb) {
43      res = &i;
44  } else {
45      res = 0;
46  }
47  return *res; // no warning
48}
49
50int testMultipleLevelsOfSubclassing1() {
51  BB bb;
52  B *pb = &bb;
53  A *pa = pb;
54  B *b = dynamic_cast<B*>(pa);
55  const int* res = 0;
56  static const int i = 5;
57  if (b) {
58      res = &i;
59  } else {
60      res = 0;
61  }
62  return *res; // no warning
63}
64
65int testMultipleLevelsOfSubclassing2() {
66  BB bb;
67  A *pbb = &bb;
68  B *b = dynamic_cast<B*>(pbb);
69  BB *s = dynamic_cast<BB*>(b);
70  const int* res = 0;
71  static const int i = 5;
72  if (s) {
73      res = &i;
74  } else {
75      res = 0;
76  }
77  return *res; // no warning
78}
79
80int testMultipleLevelsOfSubclassing3() {
81  BB bb;
82  A *pbb = &bb;
83  B *b = dynamic_cast<B*>(pbb);
84  return b->m; // no warning
85}
86
87int testLHS() {
88    B aa;
89    A *a = &aa;
90    return (dynamic_cast<B*>(a))->m;
91}
92
93int testLHS2() {
94    B aa;
95    A *a = &aa;
96    return (*dynamic_cast<B*>(a)).m;
97}
98
99int testDynCastUnknown2(class A *a) {
100  B *b = dynamic_cast<B*>(a);
101  return b->m; // no warning
102}
103
104int testDynCastUnknown(class A *a) {
105  B *b = dynamic_cast<B*>(a);
106  const int* res = 0;
107  static const int i = 5;
108  if (b) {
109    res = &i;
110  } else {
111    res = 0;
112  }
113  return *res; // expected-warning {{Dereference of null pointer}}
114}
115
116int testDynCastFail2() {
117  C c;
118  A *pa = &c;
119  B *b = dynamic_cast<B*>(pa);
120  return b->m; // expected-warning {{dereference of a null pointer}}
121}
122
123int testLHSFail() {
124    C c;
125    A *a = &c;
126    return (*dynamic_cast<B*>(a)).m; // expected-warning {{Dereference of null pointer}}
127}
128
129int testBaseToDerivedFail() {
130  A a;
131  B *b = dynamic_cast<B*>(&a);
132  return b->m; // expected-warning {{dereference of a null pointer}}
133}
134
135int testConstZeroFail() {
136  B *b = dynamic_cast<B*>((A *)0);
137  return b->m; // expected-warning {{dereference of a null pointer}}
138}
139
140int testConstZeroFail2() {
141  A *a = 0;
142  B *b = dynamic_cast<B*>(a);
143  return b->m; // expected-warning {{dereference of a null pointer}}
144}
145
146int testUpcast() {
147  B b;
148  A *a = dynamic_cast<A*>(&b);
149  const int* res = 0;
150  static const int i = 5;
151  if (a) {
152      res = &i;
153  } else {
154      res = 0;
155  }
156  return *res; // no warning
157}
158
159int testCastToVoidStar() {
160  A a;
161  void *b = dynamic_cast<void*>(&a);
162  const int* res = 0;
163  static const int i = 5;
164  if (b) {
165      res = &i;
166  } else {
167      res = 0;
168  }
169  return *res; // no warning
170}
171
172int testReferenceSuccesfulCast() {
173  B rb;
174  B &b = dynamic_cast<B&>(rb);
175  int *x = 0;
176  return *x; // expected-warning {{Dereference of null pointer}}
177}
178
179int testReferenceFailedCast() {
180  A a;
181  B &b = dynamic_cast<B&>(a);
182  int *x = 0;
183  return *x; // no warning (An exception is thrown by the cast.)
184}
185
186// Here we allow any outcome of the cast and this is good because there is a
187// situation where this will fail. So if the user has written the code in this
188// way, we assume they expect the cast to succeed.
189// Note, this might need special handling if we track types of symbolic casts
190// and use them for dynamic_cast handling.
191int testDynCastMostLikelyWillFail(C *c) {
192  B *b = 0;
193  b = dynamic_cast<B*>(c);
194  const int* res = 0;
195  static const int i = 5;
196  if (b) {
197      res = &i;
198  } else {
199      res = 0;
200  }
201
202  // Note: IPA is turned off for this test because the code below shows how the
203  // dynamic_cast could succeed.
204  return *res; // expected-warning{{Dereference of null pointer}}
205}
206
207class M : public B, public C {};
208void callTestDynCastMostLikelyWillFail() {
209  M m;
210  testDynCastMostLikelyWillFail(&m);
211}
212
213
214void testDynCastToMiddleClass () {
215  class BBB : public BB {};
216  BBB obj;
217  A &ref = obj;
218
219  // These didn't always correctly layer base regions.
220  B *ptr = dynamic_cast<B*>(&ref);
221  clang_analyzer_eval(ptr != 0); // expected-warning{{TRUE}}
222
223  // This is actually statically resolved to be a DerivedToBase cast.
224  ptr = dynamic_cast<B*>(&obj);
225  clang_analyzer_eval(ptr != 0); // expected-warning{{TRUE}}
226}
227
228
229// -----------------------------
230// False positives/negatives.
231// -----------------------------
232
233// Due to symbolic regions not being typed.
234int testDynCastFalsePositive(BB *c) {
235  B *b = 0;
236  b = dynamic_cast<B*>(c);
237  const int* res = 0;
238  static const int i = 5;
239  if (b) {
240      res = &i;
241  } else {
242      res = 0;
243  }
244  return *res; // expected-warning{{Dereference of null pointer}}
245}
246
247// Does not work when we new an object.
248int testDynCastFail3() {
249  A *a = new A();
250  B *b = dynamic_cast<B*>(a);
251  return b->m;
252}
253
254