1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
2 // RUN: %clang_cc1 -analyze -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
f()17 void B::f() {
18 x = 3;
19 }
20
21
22 class C : public B {
23 public:
g()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:
getX()39 int getX() { return x; }
40 };
41
42 class C : public virtual A {
43 public:
setX()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
test()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:
getX()74 int getX() { return x; }
75 };
76
77 class CI : public virtual Intermediate {
78 public:
setX()79 void setX() { x = 42; }
80 };
81
82 class DI : public BI, public CI {};
83
testIntermediate()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
testCast(A * a)102 bool testCast(A *a) {
103 return dynamic_cast<B*>(a) && dynamic_cast<C*>(a);
104 }
105
test()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
testCast(B * a)123 bool testCast(B *a) {
124 return dynamic_cast<C*>(a);
125 }
126
test()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
testVirtual()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
getX(const Base & obj)154 int getX(const Base &obj) {
155 return obj.x;
156 }
157
getY(const Derived & obj)158 int getY(const Derived &obj) {
159 return obj.y;
160 }
161
testDerived()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
testDoubleDerived()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
getY(const OffsetDerived & obj)209 int getY(const OffsetDerived &obj) {
210 return obj.y;
211 }
212
testDerived()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
testDoubleDerived()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
getY(const DerivedVTBL & obj)258 int getY(const DerivedVTBL &obj) {
259 return obj.y;
260 }
261
getZ(const DoubleDerivedVTBL & obj)262 int getZ(const DoubleDerivedVTBL &obj) {
263 return obj.z;
264 }
265
testDerived()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
testDoubleDerived()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;
NonTrivialCopyLazyBindings::Nested::NonTrivialCopy312 NonTrivialCopy() {}
NonTrivialCopyLazyBindings::Nested::NonTrivialCopy313 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
WrapperLazyBindings::Nested::Wrapper324 Wrapper(const FullyDerived &d) : d(d), zz(0) {}
325 };
326
test5()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();
get()344 int get() { return value; }
345
346 int value;
347 };
348
349 class Derived : public Base {
350 public:
351 virtual int bar();
352 };
353
test(Derived d)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:
f()382 virtual int f() {
383 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
384 return i + j;
385 }
386 };
387
testXXX()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:
f()410 virtual int f() {
411 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
412 return i + j;
413 }
414 };
415
test()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:
f()438 virtual int f() {
439 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
440 return i + j;
441 }
442 };
443
test()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
f(Incomplete * i)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.
g()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