1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s |
2 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -DCONSTRUCTORS=1 -analyzer-config c++-inlining=constructors -verify %s |
3 | |
4 | void clang_analyzer_eval(bool); |
5 | void clang_analyzer_checkInlined(bool); |
6 | |
7 | class A { |
8 | protected: |
9 | int x; |
10 | }; |
11 | |
12 | class B : public A { |
13 | public: |
14 | void f(); |
15 | }; |
16 | |
17 | void B::f() { |
18 | x = 3; |
19 | } |
20 | |
21 | |
22 | class C : public B { |
23 | public: |
24 | void g() { |
25 | // This used to crash because we are upcasting through two bases. |
26 | x = 5; |
27 | } |
28 | }; |
29 | |
30 | |
31 | namespace VirtualBaseClasses { |
32 | class A { |
33 | protected: |
34 | int x; |
35 | }; |
36 | |
37 | class B : public virtual A { |
38 | public: |
39 | int getX() { return x; } |
40 | }; |
41 | |
42 | class C : public virtual A { |
43 | public: |
44 | void setX() { x = 42; } |
45 | }; |
46 | |
47 | class D : public B, public C {}; |
48 | class DV : virtual public B, public C {}; |
49 | class DV2 : public B, virtual public C {}; |
50 | |
51 | void test() { |
52 | D d; |
53 | d.setX(); |
54 | clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}} |
55 | |
56 | DV dv; |
57 | dv.setX(); |
58 | clang_analyzer_eval(dv.getX() == 42); // expected-warning{{TRUE}} |
59 | |
60 | DV2 dv2; |
61 | dv2.setX(); |
62 | clang_analyzer_eval(dv2.getX() == 42); // expected-warning{{TRUE}} |
63 | } |
64 | |
65 | |
66 | // Make sure we're consistent about the offset of the A subobject within an |
67 | // Intermediate virtual base class. |
68 | class Padding1 { int unused; }; |
69 | class Padding2 { int unused; }; |
70 | class Intermediate : public Padding1, public A, public Padding2 {}; |
71 | |
72 | class BI : public virtual Intermediate { |
73 | public: |
74 | int getX() { return x; } |
75 | }; |
76 | |
77 | class CI : public virtual Intermediate { |
78 | public: |
79 | void setX() { x = 42; } |
80 | }; |
81 | |
82 | class DI : public BI, public CI {}; |
83 | |
84 | void testIntermediate() { |
85 | DI d; |
86 | d.setX(); |
87 | clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}} |
88 | } |
89 | } |
90 | |
91 | |
92 | namespace DynamicVirtualUpcast { |
93 | class A { |
94 | public: |
95 | virtual ~A(); |
96 | }; |
97 | |
98 | class B : virtual public A {}; |
99 | class C : virtual public B {}; |
100 | class D : virtual public C {}; |
101 | |
102 | bool testCast(A *a) { |
103 | return dynamic_cast<B*>(a) && dynamic_cast<C*>(a); |
104 | } |
105 | |
106 | void test() { |
107 | D d; |
108 | clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}} |
109 | } |
110 | } |
111 | |
112 | namespace DynamicMultipleInheritanceUpcast { |
113 | class B { |
114 | public: |
115 | virtual ~B(); |
116 | }; |
117 | class C { |
118 | public: |
119 | virtual ~C(); |
120 | }; |
121 | class D : public B, public C {}; |
122 | |
123 | bool testCast(B *a) { |
124 | return dynamic_cast<C*>(a); |
125 | } |
126 | |
127 | void test() { |
128 | D d; |
129 | clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}} |
130 | } |
131 | |
132 | |
133 | class DV : virtual public B, virtual public C {}; |
134 | |
135 | void testVirtual() { |
136 | DV d; |
137 | clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}} |
138 | } |
139 | } |
140 | |
141 | namespace LazyBindings { |
142 | struct Base { |
143 | int x; |
144 | }; |
145 | |
146 | struct Derived : public Base { |
147 | int y; |
148 | }; |
149 | |
150 | struct DoubleDerived : public Derived { |
151 | int z; |
152 | }; |
153 | |
154 | int getX(const Base &obj) { |
155 | return obj.x; |
156 | } |
157 | |
158 | int getY(const Derived &obj) { |
159 | return obj.y; |
160 | } |
161 | |
162 | void testDerived() { |
163 | Derived d; |
164 | d.x = 1; |
165 | d.y = 2; |
166 | clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} |
167 | clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} |
168 | |
169 | Base b(d); |
170 | clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} |
171 | |
172 | Derived d2(d); |
173 | clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} |
174 | clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} |
175 | } |
176 | |
177 | void testDoubleDerived() { |
178 | DoubleDerived d; |
179 | d.x = 1; |
180 | d.y = 2; |
181 | clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} |
182 | clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} |
183 | |
184 | Base b(d); |
185 | clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} |
186 | |
187 | Derived d2(d); |
188 | clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} |
189 | clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} |
190 | |
191 | DoubleDerived d3(d); |
192 | clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}} |
193 | clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}} |
194 | } |
195 | |
196 | namespace WithOffset { |
197 | struct Offset { |
198 | int padding; |
199 | }; |
200 | |
201 | struct OffsetDerived : private Offset, public Base { |
202 | int y; |
203 | }; |
204 | |
205 | struct DoubleOffsetDerived : public OffsetDerived { |
206 | int z; |
207 | }; |
208 | |
209 | int getY(const OffsetDerived &obj) { |
210 | return obj.y; |
211 | } |
212 | |
213 | void testDerived() { |
214 | OffsetDerived d; |
215 | d.x = 1; |
216 | d.y = 2; |
217 | clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} |
218 | clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} |
219 | |
220 | Base b(d); |
221 | clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} |
222 | |
223 | OffsetDerived d2(d); |
224 | clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} |
225 | clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} |
226 | } |
227 | |
228 | void testDoubleDerived() { |
229 | DoubleOffsetDerived d; |
230 | d.x = 1; |
231 | d.y = 2; |
232 | clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} |
233 | clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} |
234 | |
235 | Base b(d); |
236 | clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} |
237 | |
238 | OffsetDerived d2(d); |
239 | clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} |
240 | clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} |
241 | |
242 | DoubleOffsetDerived d3(d); |
243 | clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}} |
244 | clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}} |
245 | } |
246 | } |
247 | |
248 | namespace WithVTable { |
249 | struct DerivedVTBL : public Base { |
250 | int y; |
251 | virtual void method(); |
252 | }; |
253 | |
254 | struct DoubleDerivedVTBL : public DerivedVTBL { |
255 | int z; |
256 | }; |
257 | |
258 | int getY(const DerivedVTBL &obj) { |
259 | return obj.y; |
260 | } |
261 | |
262 | int getZ(const DoubleDerivedVTBL &obj) { |
263 | return obj.z; |
264 | } |
265 | |
266 | void testDerived() { |
267 | DerivedVTBL d; |
268 | d.x = 1; |
269 | d.y = 2; |
270 | clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} |
271 | clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} |
272 | |
273 | Base b(d); |
274 | clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} |
275 | |
276 | #if CONSTRUCTORS |
277 | DerivedVTBL d2(d); |
278 | clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} |
279 | clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} |
280 | #endif |
281 | } |
282 | |
283 | #if CONSTRUCTORS |
284 | void testDoubleDerived() { |
285 | DoubleDerivedVTBL d; |
286 | d.x = 1; |
287 | d.y = 2; |
288 | d.z = 3; |
289 | clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} |
290 | clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} |
291 | clang_analyzer_eval(getZ(d) == 3); // expected-warning{{TRUE}} |
292 | |
293 | Base b(d); |
294 | clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} |
295 | |
296 | DerivedVTBL d2(d); |
297 | clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} |
298 | clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} |
299 | |
300 | DoubleDerivedVTBL d3(d); |
301 | clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}} |
302 | clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}} |
303 | clang_analyzer_eval(getZ(d3) == 3); // expected-warning{{TRUE}} |
304 | } |
305 | #endif |
306 | } |
307 | |
308 | #if CONSTRUCTORS |
309 | namespace Nested { |
310 | struct NonTrivialCopy { |
311 | int padding; |
312 | NonTrivialCopy() {} |
313 | NonTrivialCopy(const NonTrivialCopy &) {} |
314 | }; |
315 | |
316 | struct FullyDerived : private NonTrivialCopy, public Derived { |
317 | int z; |
318 | }; |
319 | |
320 | struct Wrapper { |
321 | FullyDerived d; |
322 | int zz; |
323 | |
324 | Wrapper(const FullyDerived &d) : d(d), zz(0) {} |
325 | }; |
326 | |
327 | void test5() { |
328 | Wrapper w((FullyDerived())); |
329 | w.d.x = 1; |
330 | |
331 | Wrapper w2(w); |
332 | clang_analyzer_eval(getX(w2.d) == 1); // expected-warning{{TRUE}} |
333 | } |
334 | } |
335 | #endif |
336 | } |
337 | |
338 | namespace Redeclaration { |
339 | class Base; |
340 | |
341 | class Base { |
342 | public: |
343 | virtual int foo(); |
344 | int get() { return value; } |
345 | |
346 | int value; |
347 | }; |
348 | |
349 | class Derived : public Base { |
350 | public: |
351 | virtual int bar(); |
352 | }; |
353 | |
354 | void test(Derived d) { |
355 | d.foo(); // don't crash |
356 | d.bar(); // sanity check |
357 | |
358 | Base &b = d; |
359 | b.foo(); // don't crash |
360 | |
361 | d.value = 42; // don't crash |
362 | clang_analyzer_eval(d.get() == 42); // expected-warning{{TRUE}} |
363 | clang_analyzer_eval(b.get() == 42); // expected-warning{{TRUE}} |
364 | } |
365 | }; |
366 | |
367 | namespace PR15394 { |
368 | namespace Original { |
369 | class Base { |
370 | public: |
371 | virtual int f() = 0; |
372 | int i; |
373 | }; |
374 | |
375 | class Derived1 : public Base { |
376 | public: |
377 | int j; |
378 | }; |
379 | |
380 | class Derived2 : public Derived1 { |
381 | public: |
382 | virtual int f() { |
383 | clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} |
384 | return i + j; |
385 | } |
386 | }; |
387 | |
388 | void testXXX() { |
389 | Derived1 *d1p = reinterpret_cast<Derived1*>(new Derived2); |
390 | d1p->i = 1; |
391 | d1p->j = 2; |
392 | clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}} |
393 | } |
394 | } |
395 | |
396 | namespace VirtualInDerived { |
397 | class Base { |
398 | public: |
399 | int i; |
400 | }; |
401 | |
402 | class Derived1 : public Base { |
403 | public: |
404 | virtual int f() = 0; |
405 | int j; |
406 | }; |
407 | |
408 | class Derived2 : public Derived1 { |
409 | public: |
410 | virtual int f() { |
411 | clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} |
412 | return i + j; |
413 | } |
414 | }; |
415 | |
416 | void test() { |
417 | Derived1 *d1p = reinterpret_cast<Derived1*>(new Derived2); |
418 | d1p->i = 1; |
419 | d1p->j = 2; |
420 | clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}} |
421 | } |
422 | } |
423 | |
424 | namespace NoCast { |
425 | class Base { |
426 | public: |
427 | int i; |
428 | }; |
429 | |
430 | class Derived1 : public Base { |
431 | public: |
432 | virtual int f() = 0; |
433 | int j; |
434 | }; |
435 | |
436 | class Derived2 : public Derived1 { |
437 | public: |
438 | virtual int f() { |
439 | clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} |
440 | return i + j; |
441 | } |
442 | }; |
443 | |
444 | void test() { |
445 | Derived1 *d1p = new Derived2; |
446 | d1p->i = 1; |
447 | d1p->j = 2; |
448 | clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}} |
449 | } |
450 | } |
451 | }; |
452 | |
453 | namespace Bug16309 { |
454 | struct Incomplete; |
455 | |
456 | struct Base { virtual ~Base(); }; |
457 | |
458 | struct Derived : public Base { int x; }; |
459 | |
460 | void* f(Incomplete *i) { |
461 | Base *b = reinterpret_cast<Base *>(i); |
462 | // This used to crash because of the reinterpret_cast above. |
463 | Derived *d = dynamic_cast<Derived *>(b); |
464 | return d; |
465 | } |
466 | |
467 | // And check that reinterpret+dynamic casts work correctly after the fix. |
468 | void g() { |
469 | Derived d; |
470 | d.x = 47; |
471 | Base *b = &d; |
472 | Incomplete *i = reinterpret_cast<Incomplete *>(b); |
473 | Base *b2 = reinterpret_cast<Base *>(i); |
474 | Derived *d2 = dynamic_cast<Derived *>(b2); |
475 | clang_analyzer_eval(d2->x == 47); // expected-warning{{TRUE}} |
476 | } |
477 | } |
478 | |