1 | // RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -DI386 -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify -analyzer-config eagerly-assume=false %s |
2 | // RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -DI386 -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify -DTEST_INLINABLE_ALLOCATORS -analyzer-config eagerly-assume=false %s |
3 | // RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin12 -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify -analyzer-config eagerly-assume=false %s |
4 | // RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin12 -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify -DTEST_INLINABLE_ALLOCATORS -analyzer-config eagerly-assume=false %s |
5 | |
6 | #include "Inputs/system-header-simulator-cxx.h" |
7 | |
8 | void clang_analyzer_eval(bool); |
9 | void clang_analyzer_checkInlined(bool); |
10 | |
11 | // A simplified version of std::move. |
12 | template <typename T> |
13 | T &&move(T &obj) { |
14 | return static_cast<T &&>(obj); |
15 | } |
16 | |
17 | |
18 | struct Wrapper { |
19 | __strong id obj; |
20 | }; |
21 | |
22 | void test() { |
23 | Wrapper w; |
24 | // force a diagnostic |
25 | *(char *)0 = 1; // expected-warning{{Dereference of null pointer}} |
26 | } |
27 | |
28 | |
29 | struct IntWrapper { |
30 | int x; |
31 | }; |
32 | |
33 | void testCopyConstructor() { |
34 | IntWrapper a; |
35 | a.x = 42; |
36 | |
37 | IntWrapper b(a); |
38 | clang_analyzer_eval(b.x == 42); // expected-warning{{TRUE}} |
39 | } |
40 | |
41 | struct NonPODIntWrapper { |
42 | int x; |
43 | |
44 | virtual int get(); |
45 | }; |
46 | |
47 | void testNonPODCopyConstructor() { |
48 | NonPODIntWrapper a; |
49 | a.x = 42; |
50 | |
51 | NonPODIntWrapper b(a); |
52 | clang_analyzer_eval(b.x == 42); // expected-warning{{TRUE}} |
53 | } |
54 | |
55 | |
56 | namespace ConstructorVirtualCalls { |
57 | class A { |
58 | public: |
59 | int *out1, *out2, *out3; |
60 | |
61 | virtual int get() { return 1; } |
62 | |
63 | A(int *out1) { |
64 | *out1 = get(); |
65 | } |
66 | }; |
67 | |
68 | class B : public A { |
69 | public: |
70 | virtual int get() { return 2; } |
71 | |
72 | B(int *out1, int *out2) : A(out1) { |
73 | *out2 = get(); |
74 | } |
75 | }; |
76 | |
77 | class C : public B { |
78 | public: |
79 | virtual int get() { return 3; } |
80 | |
81 | C(int *out1, int *out2, int *out3) : B(out1, out2) { |
82 | *out3 = get(); |
83 | } |
84 | }; |
85 | |
86 | void test() { |
87 | int a, b, c; |
88 | |
89 | C obj(&a, &b, &c); |
90 | clang_analyzer_eval(a == 1); // expected-warning{{TRUE}} |
91 | clang_analyzer_eval(b == 2); // expected-warning{{TRUE}} |
92 | clang_analyzer_eval(c == 3); // expected-warning{{TRUE}} |
93 | |
94 | clang_analyzer_eval(obj.get() == 3); // expected-warning{{TRUE}} |
95 | |
96 | // Sanity check for devirtualization. |
97 | A *base = &obj; |
98 | clang_analyzer_eval(base->get() == 3); // expected-warning{{TRUE}} |
99 | } |
100 | } |
101 | |
102 | namespace TemporaryConstructor { |
103 | class BoolWrapper { |
104 | public: |
105 | BoolWrapper() { |
106 | clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} |
107 | value = true; |
108 | } |
109 | bool value; |
110 | }; |
111 | |
112 | void test() { |
113 | // PR13717 - Don't crash when a CXXTemporaryObjectExpr is inlined. |
114 | if (BoolWrapper().value) |
115 | return; |
116 | } |
117 | } |
118 | |
119 | |
120 | namespace ConstructorUsedAsRValue { |
121 | using TemporaryConstructor::BoolWrapper; |
122 | |
123 | bool extractValue(BoolWrapper b) { |
124 | return b.value; |
125 | } |
126 | |
127 | void test() { |
128 | bool result = extractValue(BoolWrapper()); |
129 | clang_analyzer_eval(result); // expected-warning{{TRUE}} |
130 | } |
131 | } |
132 | |
133 | namespace PODUninitialized { |
134 | class POD { |
135 | public: |
136 | int x, y; |
137 | }; |
138 | |
139 | class PODWrapper { |
140 | public: |
141 | POD p; |
142 | }; |
143 | |
144 | class NonPOD { |
145 | public: |
146 | int x, y; |
147 | |
148 | NonPOD() {} |
149 | NonPOD(const NonPOD &Other) |
150 | : x(Other.x), y(Other.y) // expected-warning {{undefined}} |
151 | { |
152 | } |
153 | NonPOD(NonPOD &&Other) |
154 | : x(Other.x), y(Other.y) // expected-warning {{undefined}} |
155 | { |
156 | } |
157 | |
158 | NonPOD &operator=(const NonPOD &Other) |
159 | { |
160 | x = Other.x; |
161 | y = Other.y; // expected-warning {{undefined}} |
162 | return *this; |
163 | } |
164 | NonPOD &operator=(NonPOD &&Other) |
165 | { |
166 | x = Other.x; |
167 | y = Other.y; // expected-warning {{undefined}} |
168 | return *this; |
169 | } |
170 | }; |
171 | |
172 | class NonPODWrapper { |
173 | public: |
174 | class Inner { |
175 | public: |
176 | int x, y; |
177 | |
178 | Inner() {} |
179 | Inner(const Inner &Other) |
180 | : x(Other.x), y(Other.y) // expected-warning {{undefined}} |
181 | { |
182 | } |
183 | Inner(Inner &&Other) |
184 | : x(Other.x), y(Other.y) // expected-warning {{undefined}} |
185 | { |
186 | } |
187 | |
188 | Inner &operator=(const Inner &Other) |
189 | { |
190 | x = Other.x; // expected-warning {{undefined}} |
191 | y = Other.y; |
192 | return *this; |
193 | } |
194 | Inner &operator=(Inner &&Other) |
195 | { |
196 | x = Other.x; // expected-warning {{undefined}} |
197 | y = Other.y; |
198 | return *this; |
199 | } |
200 | }; |
201 | |
202 | Inner p; |
203 | }; |
204 | |
205 | void testPOD(const POD &pp) { |
206 | POD p; |
207 | p.x = 1; |
208 | POD p2 = p; // no-warning |
209 | clang_analyzer_eval(p2.x == 1); // expected-warning{{TRUE}} |
210 | POD p3 = move(p); // no-warning |
211 | clang_analyzer_eval(p3.x == 1); // expected-warning{{TRUE}} |
212 | |
213 | // Use rvalues as well. |
214 | clang_analyzer_eval(POD(p3).x == 1); // expected-warning{{TRUE}} |
215 | |
216 | // Copy from symbolic references correctly. |
217 | POD p4 = pp; |
218 | // Make sure that p4.x contains a symbol after copy. |
219 | if (p4.x > 0) |
220 | clang_analyzer_eval(p4.x > 0); // expected-warning{{TRUE}} |
221 | // FIXME: Element region gets in the way, so these aren't the same symbols |
222 | // as they should be. |
223 | clang_analyzer_eval(pp.x == p4.x); // expected-warning{{UNKNOWN}} |
224 | |
225 | PODWrapper w; |
226 | w.p.y = 1; |
227 | PODWrapper w2 = w; // no-warning |
228 | clang_analyzer_eval(w2.p.y == 1); // expected-warning{{TRUE}} |
229 | PODWrapper w3 = move(w); // no-warning |
230 | clang_analyzer_eval(w3.p.y == 1); // expected-warning{{TRUE}} |
231 | |
232 | // Use rvalues as well. |
233 | clang_analyzer_eval(PODWrapper(w3).p.y == 1); // expected-warning{{TRUE}} |
234 | } |
235 | |
236 | void testNonPOD() { |
237 | NonPOD p; |
238 | p.x = 1; |
239 | NonPOD p2 = p; |
240 | } |
241 | |
242 | void testNonPODMove() { |
243 | NonPOD p; |
244 | p.x = 1; |
245 | NonPOD p2 = move(p); |
246 | } |
247 | |
248 | void testNonPODWrapper() { |
249 | NonPODWrapper w; |
250 | w.p.y = 1; |
251 | NonPODWrapper w2 = w; |
252 | } |
253 | |
254 | void testNonPODWrapperMove() { |
255 | NonPODWrapper w; |
256 | w.p.y = 1; |
257 | NonPODWrapper w2 = move(w); |
258 | } |
259 | |
260 | // Not strictly about constructors, but trivial assignment operators should |
261 | // essentially work the same way. |
262 | namespace AssignmentOperator { |
263 | void testPOD() { |
264 | POD p; |
265 | p.x = 1; |
266 | POD p2; |
267 | p2 = p; // no-warning |
268 | clang_analyzer_eval(p2.x == 1); // expected-warning{{TRUE}} |
269 | POD p3; |
270 | p3 = move(p); // no-warning |
271 | clang_analyzer_eval(p3.x == 1); // expected-warning{{TRUE}} |
272 | |
273 | PODWrapper w; |
274 | w.p.y = 1; |
275 | PODWrapper w2; |
276 | w2 = w; // no-warning |
277 | clang_analyzer_eval(w2.p.y == 1); // expected-warning{{TRUE}} |
278 | PODWrapper w3; |
279 | w3 = move(w); // no-warning |
280 | clang_analyzer_eval(w3.p.y == 1); // expected-warning{{TRUE}} |
281 | } |
282 | |
283 | void testReturnValue() { |
284 | POD p; |
285 | p.x = 1; |
286 | POD p2; |
287 | clang_analyzer_eval(&(p2 = p) == &p2); // expected-warning{{TRUE}} |
288 | |
289 | PODWrapper w; |
290 | w.p.y = 1; |
291 | PODWrapper w2; |
292 | clang_analyzer_eval(&(w2 = w) == &w2); // expected-warning{{TRUE}} |
293 | } |
294 | |
295 | void testNonPOD() { |
296 | NonPOD p; |
297 | p.x = 1; |
298 | NonPOD p2; |
299 | p2 = p; |
300 | } |
301 | |
302 | void testNonPODMove() { |
303 | NonPOD p; |
304 | p.x = 1; |
305 | NonPOD p2; |
306 | p2 = move(p); |
307 | } |
308 | |
309 | void testNonPODWrapper() { |
310 | NonPODWrapper w; |
311 | w.p.y = 1; |
312 | NonPODWrapper w2; |
313 | w2 = w; |
314 | } |
315 | |
316 | void testNonPODWrapperMove() { |
317 | NonPODWrapper w; |
318 | w.p.y = 1; |
319 | NonPODWrapper w2; |
320 | w2 = move(w); |
321 | } |
322 | } |
323 | } |
324 | |
325 | namespace ArrayMembers { |
326 | struct Primitive { |
327 | int values[3]; |
328 | }; |
329 | |
330 | void testPrimitive() { |
331 | Primitive a = { { 1, 2, 3 } }; |
332 | |
333 | clang_analyzer_eval(a.values[0] == 1); // expected-warning{{TRUE}} |
334 | clang_analyzer_eval(a.values[1] == 2); // expected-warning{{TRUE}} |
335 | clang_analyzer_eval(a.values[2] == 3); // expected-warning{{TRUE}} |
336 | |
337 | Primitive b = a; |
338 | |
339 | clang_analyzer_eval(b.values[0] == 1); // expected-warning{{TRUE}} |
340 | clang_analyzer_eval(b.values[1] == 2); // expected-warning{{TRUE}} |
341 | clang_analyzer_eval(b.values[2] == 3); // expected-warning{{TRUE}} |
342 | |
343 | Primitive c; |
344 | c = b; |
345 | |
346 | clang_analyzer_eval(c.values[0] == 1); // expected-warning{{TRUE}} |
347 | clang_analyzer_eval(c.values[1] == 2); // expected-warning{{TRUE}} |
348 | clang_analyzer_eval(c.values[2] == 3); // expected-warning{{TRUE}} |
349 | } |
350 | |
351 | struct NestedPrimitive { |
352 | int values[2][3]; |
353 | }; |
354 | |
355 | void testNestedPrimitive() { |
356 | NestedPrimitive a = { { { 0, 0, 0 }, { 1, 2, 3 } } }; |
357 | |
358 | clang_analyzer_eval(a.values[1][0] == 1); // expected-warning{{TRUE}} |
359 | clang_analyzer_eval(a.values[1][1] == 2); // expected-warning{{TRUE}} |
360 | clang_analyzer_eval(a.values[1][2] == 3); // expected-warning{{TRUE}} |
361 | |
362 | NestedPrimitive b = a; |
363 | |
364 | clang_analyzer_eval(b.values[1][0] == 1); // expected-warning{{TRUE}} |
365 | clang_analyzer_eval(b.values[1][1] == 2); // expected-warning{{TRUE}} |
366 | clang_analyzer_eval(b.values[1][2] == 3); // expected-warning{{TRUE}} |
367 | |
368 | NestedPrimitive c; |
369 | c = b; |
370 | |
371 | clang_analyzer_eval(c.values[1][0] == 1); // expected-warning{{TRUE}} |
372 | clang_analyzer_eval(c.values[1][1] == 2); // expected-warning{{TRUE}} |
373 | clang_analyzer_eval(c.values[1][2] == 3); // expected-warning{{TRUE}} |
374 | } |
375 | |
376 | struct POD { |
377 | IntWrapper values[3]; |
378 | }; |
379 | |
380 | void testPOD() { |
381 | POD a = { { { 1 }, { 2 }, { 3 } } }; |
382 | |
383 | clang_analyzer_eval(a.values[0].x == 1); // expected-warning{{TRUE}} |
384 | clang_analyzer_eval(a.values[1].x == 2); // expected-warning{{TRUE}} |
385 | clang_analyzer_eval(a.values[2].x == 3); // expected-warning{{TRUE}} |
386 | |
387 | POD b = a; |
388 | |
389 | clang_analyzer_eval(b.values[0].x == 1); // expected-warning{{TRUE}} |
390 | clang_analyzer_eval(b.values[1].x == 2); // expected-warning{{TRUE}} |
391 | clang_analyzer_eval(b.values[2].x == 3); // expected-warning{{TRUE}} |
392 | |
393 | POD c; |
394 | c = b; |
395 | |
396 | clang_analyzer_eval(c.values[0].x == 1); // expected-warning{{TRUE}} |
397 | clang_analyzer_eval(c.values[1].x == 2); // expected-warning{{TRUE}} |
398 | clang_analyzer_eval(c.values[2].x == 3); // expected-warning{{TRUE}} |
399 | } |
400 | |
401 | struct NestedPOD { |
402 | IntWrapper values[2][3]; |
403 | }; |
404 | |
405 | void testNestedPOD() { |
406 | NestedPOD a = { { { { 0 }, { 0 }, { 0 } }, { { 1 }, { 2 }, { 3 } } } }; |
407 | |
408 | clang_analyzer_eval(a.values[1][0].x == 1); // expected-warning{{TRUE}} |
409 | clang_analyzer_eval(a.values[1][1].x == 2); // expected-warning{{TRUE}} |
410 | clang_analyzer_eval(a.values[1][2].x == 3); // expected-warning{{TRUE}} |
411 | |
412 | NestedPOD b = a; |
413 | |
414 | clang_analyzer_eval(b.values[1][0].x == 1); // expected-warning{{TRUE}} |
415 | clang_analyzer_eval(b.values[1][1].x == 2); // expected-warning{{TRUE}} |
416 | clang_analyzer_eval(b.values[1][2].x == 3); // expected-warning{{TRUE}} |
417 | |
418 | NestedPOD c; |
419 | c = b; |
420 | |
421 | clang_analyzer_eval(c.values[1][0].x == 1); // expected-warning{{TRUE}} |
422 | clang_analyzer_eval(c.values[1][1].x == 2); // expected-warning{{TRUE}} |
423 | clang_analyzer_eval(c.values[1][2].x == 3); // expected-warning{{TRUE}} |
424 | } |
425 | |
426 | struct NonPOD { |
427 | NonPODIntWrapper values[3]; |
428 | }; |
429 | |
430 | void testNonPOD() { |
431 | NonPOD a; |
432 | a.values[0].x = 1; |
433 | a.values[1].x = 2; |
434 | a.values[2].x = 3; |
435 | |
436 | clang_analyzer_eval(a.values[0].x == 1); // expected-warning{{TRUE}} |
437 | clang_analyzer_eval(a.values[1].x == 2); // expected-warning{{TRUE}} |
438 | clang_analyzer_eval(a.values[2].x == 3); // expected-warning{{TRUE}} |
439 | |
440 | NonPOD b = a; |
441 | |
442 | clang_analyzer_eval(b.values[0].x == 1); // expected-warning{{UNKNOWN}} |
443 | clang_analyzer_eval(b.values[1].x == 2); // expected-warning{{UNKNOWN}} |
444 | clang_analyzer_eval(b.values[2].x == 3); // expected-warning{{UNKNOWN}} |
445 | |
446 | NonPOD c; |
447 | c = b; |
448 | |
449 | clang_analyzer_eval(c.values[0].x == 1); // expected-warning{{UNKNOWN}} |
450 | clang_analyzer_eval(c.values[1].x == 2); // expected-warning{{UNKNOWN}} |
451 | clang_analyzer_eval(c.values[2].x == 3); // expected-warning{{UNKNOWN}} |
452 | } |
453 | |
454 | struct NestedNonPOD { |
455 | NonPODIntWrapper values[2][3]; |
456 | }; |
457 | |
458 | void testNestedNonPOD() { |
459 | NestedNonPOD a; |
460 | a.values[0][0].x = 0; |
461 | a.values[0][1].x = 0; |
462 | a.values[0][2].x = 0; |
463 | a.values[1][0].x = 1; |
464 | a.values[1][1].x = 2; |
465 | a.values[1][2].x = 3; |
466 | |
467 | clang_analyzer_eval(a.values[1][0].x == 1); // expected-warning{{TRUE}} |
468 | clang_analyzer_eval(a.values[1][1].x == 2); // expected-warning{{TRUE}} |
469 | clang_analyzer_eval(a.values[1][2].x == 3); // expected-warning{{TRUE}} |
470 | |
471 | NestedNonPOD b = a; |
472 | |
473 | clang_analyzer_eval(b.values[1][0].x == 1); // expected-warning{{UNKNOWN}} |
474 | clang_analyzer_eval(b.values[1][1].x == 2); // expected-warning{{UNKNOWN}} |
475 | clang_analyzer_eval(b.values[1][2].x == 3); // expected-warning{{UNKNOWN}} |
476 | |
477 | NestedNonPOD c; |
478 | c = b; |
479 | |
480 | clang_analyzer_eval(c.values[1][0].x == 1); // expected-warning{{UNKNOWN}} |
481 | clang_analyzer_eval(c.values[1][1].x == 2); // expected-warning{{UNKNOWN}} |
482 | clang_analyzer_eval(c.values[1][2].x == 3); // expected-warning{{UNKNOWN}} |
483 | } |
484 | |
485 | struct NonPODDefaulted { |
486 | NonPODIntWrapper values[3]; |
487 | |
488 | NonPODDefaulted() = default; |
489 | NonPODDefaulted(const NonPODDefaulted &) = default; |
490 | NonPODDefaulted &operator=(const NonPODDefaulted &) = default; |
491 | }; |
492 | |
493 | void testNonPODDefaulted() { |
494 | NonPODDefaulted a; |
495 | a.values[0].x = 1; |
496 | a.values[1].x = 2; |
497 | a.values[2].x = 3; |
498 | |
499 | clang_analyzer_eval(a.values[0].x == 1); // expected-warning{{TRUE}} |
500 | clang_analyzer_eval(a.values[1].x == 2); // expected-warning{{TRUE}} |
501 | clang_analyzer_eval(a.values[2].x == 3); // expected-warning{{TRUE}} |
502 | |
503 | NonPODDefaulted b = a; |
504 | |
505 | clang_analyzer_eval(b.values[0].x == 1); // expected-warning{{UNKNOWN}} |
506 | clang_analyzer_eval(b.values[1].x == 2); // expected-warning{{UNKNOWN}} |
507 | clang_analyzer_eval(b.values[2].x == 3); // expected-warning{{UNKNOWN}} |
508 | |
509 | NonPODDefaulted c; |
510 | c = b; |
511 | |
512 | clang_analyzer_eval(c.values[0].x == 1); // expected-warning{{UNKNOWN}} |
513 | clang_analyzer_eval(c.values[1].x == 2); // expected-warning{{UNKNOWN}} |
514 | clang_analyzer_eval(c.values[2].x == 3); // expected-warning{{UNKNOWN}} |
515 | } |
516 | }; |
517 | |
518 | namespace VirtualInheritance { |
519 | int counter; |
520 | |
521 | struct base { |
522 | base() { |
523 | ++counter; |
524 | } |
525 | }; |
526 | |
527 | struct virtual_subclass : public virtual base { |
528 | virtual_subclass() {} |
529 | }; |
530 | |
531 | struct double_subclass : public virtual_subclass { |
532 | double_subclass() {} |
533 | }; |
534 | |
535 | void test() { |
536 | counter = 0; |
537 | double_subclass obj; |
538 | clang_analyzer_eval(counter == 1); // expected-warning{{TRUE}} |
539 | } |
540 | |
541 | struct double_virtual_subclass : public virtual virtual_subclass { |
542 | double_virtual_subclass() {} |
543 | }; |
544 | |
545 | void testVirtual() { |
546 | counter = 0; |
547 | double_virtual_subclass obj; |
548 | clang_analyzer_eval(counter == 1); // expected-warning{{TRUE}} |
549 | } |
550 | } |
551 | |
552 | namespace ZeroInitialization { |
553 | struct raw_pair { |
554 | int p1; |
555 | int p2; |
556 | }; |
557 | |
558 | void testVarDecl() { |
559 | raw_pair p{}; |
560 | clang_analyzer_eval(p.p1 == 0); // expected-warning{{TRUE}} |
561 | clang_analyzer_eval(p.p2 == 0); // expected-warning{{TRUE}} |
562 | } |
563 | |
564 | void testTemporary() { |
565 | clang_analyzer_eval(raw_pair().p1 == 0); // expected-warning{{TRUE}} |
566 | clang_analyzer_eval(raw_pair().p2 == 0); // expected-warning{{TRUE}} |
567 | } |
568 | |
569 | void testArray() { |
570 | raw_pair p[2] = {}; |
571 | clang_analyzer_eval(p[0].p1 == 0); // expected-warning{{TRUE}} |
572 | clang_analyzer_eval(p[0].p2 == 0); // expected-warning{{TRUE}} |
573 | clang_analyzer_eval(p[1].p1 == 0); // expected-warning{{TRUE}} |
574 | clang_analyzer_eval(p[1].p2 == 0); // expected-warning{{TRUE}} |
575 | } |
576 | |
577 | void testNew() { |
578 | raw_pair *pp = new raw_pair(); |
579 | clang_analyzer_eval(pp->p1 == 0); // expected-warning{{TRUE}} |
580 | clang_analyzer_eval(pp->p2 == 0); // expected-warning{{TRUE}} |
581 | } |
582 | |
583 | void testArrayNew() { |
584 | // FIXME: Pending proper implementation of constructors for 'new[]'. |
585 | raw_pair *p = new raw_pair[2](); |
586 | clang_analyzer_eval(p[0].p1 == 0); // expected-warning{{UNKNOWN}} |
587 | clang_analyzer_eval(p[0].p2 == 0); // expected-warning{{UNKNOWN}} |
588 | clang_analyzer_eval(p[1].p1 == 0); // expected-warning{{UNKNOWN}} |
589 | clang_analyzer_eval(p[1].p2 == 0); // expected-warning{{UNKNOWN}} |
590 | } |
591 | |
592 | struct initializing_pair { |
593 | public: |
594 | int x; |
595 | raw_pair y; |
596 | initializing_pair() : x(), y() {} |
597 | }; |
598 | |
599 | void testFieldInitializers() { |
600 | initializing_pair p; |
601 | clang_analyzer_eval(p.x == 0); // expected-warning{{TRUE}} |
602 | clang_analyzer_eval(p.y.p1 == 0); // expected-warning{{TRUE}} |
603 | clang_analyzer_eval(p.y.p2 == 0); // expected-warning{{TRUE}} |
604 | } |
605 | |
606 | struct subclass : public raw_pair { |
607 | subclass() = default; |
608 | }; |
609 | |
610 | void testSubclass() { |
611 | subclass p; |
612 | clang_analyzer_eval(p.p1 == 0); // expected-warning{{garbage}} |
613 | } |
614 | |
615 | struct initializing_subclass : public raw_pair { |
616 | initializing_subclass() : raw_pair() {} |
617 | }; |
618 | |
619 | void testInitializingSubclass() { |
620 | initializing_subclass p; |
621 | clang_analyzer_eval(p.p1 == 0); // expected-warning{{TRUE}} |
622 | clang_analyzer_eval(p.p2 == 0); // expected-warning{{TRUE}} |
623 | } |
624 | |
625 | struct pair_wrapper { |
626 | pair_wrapper() : p() {} |
627 | raw_pair p; |
628 | }; |
629 | |
630 | struct virtual_subclass : public virtual pair_wrapper { |
631 | virtual_subclass() {} |
632 | }; |
633 | |
634 | struct double_virtual_subclass : public virtual_subclass { |
635 | double_virtual_subclass() { |
636 | // This previously caused a crash because the pair_wrapper subobject was |
637 | // initialized twice. |
638 | } |
639 | }; |
640 | |
641 | class Empty { |
642 | public: |
643 | static int glob; |
644 | Empty(); // No body. |
645 | Empty(int x); // Body below. |
646 | }; |
647 | |
648 | class PairContainer : public Empty { |
649 | public: |
650 | raw_pair p; |
651 | int q; |
652 | PairContainer() : Empty(), p() { |
653 | // This previously caused a crash because the empty base class looked |
654 | // like an initialization of 'p'. |
655 | } |
656 | PairContainer(int) : Empty(), p() { |
657 | // Test inlining something else here. |
658 | } |
659 | PairContainer(double): Empty(1), p() { |
660 | clang_analyzer_eval(p.p1 == 0); // expected-warning{{TRUE}} |
661 | clang_analyzer_eval(p.p2 == 0); // expected-warning{{TRUE}} |
662 | |
663 | clang_analyzer_eval(q == 1); // expected-warning{{TRUE}} |
664 | |
665 | // This one's indeed UNKNOWN. Definitely not TRUE. |
666 | clang_analyzer_eval(p.p2 == glob); // expected-warning{{UNKNOWN}} |
667 | } |
668 | }; |
669 | |
670 | Empty::Empty(int x) { |
671 | static_cast<PairContainer *>(this)->p.p1 = x; |
672 | static_cast<PairContainer *>(this)->q = x; |
673 | // Our static member will store the old garbage values of fields that aren't |
674 | // yet initialized. It's not certainly garbage though (i.e. the constructor |
675 | // could have been called on an initialized piece of memory), so no |
676 | // uninitialized value warning here, and it should be a symbol, not |
677 | // undefined value, for later comparison. |
678 | glob = static_cast<PairContainer *>(this)->p.p2; |
679 | } |
680 | |
681 | class Empty2 { |
682 | public: |
683 | static int glob_p1, glob_p2; |
684 | Empty2(); // Body below. |
685 | }; |
686 | |
687 | class PairDoubleEmptyContainer: public Empty, public Empty2 { |
688 | public: |
689 | raw_pair p; |
690 | PairDoubleEmptyContainer(): Empty(), Empty2(), p() { |
691 | clang_analyzer_eval(p.p1 == 0); // expected-warning{{TRUE}} |
692 | clang_analyzer_eval(p.p2 == 0); // expected-warning{{TRUE}} |
693 | |
694 | // This is indeed UNKNOWN. |
695 | clang_analyzer_eval(p.p1 == glob_p1); // expected-warning{{UNKNOWN}} |
696 | clang_analyzer_eval(p.p2 == glob_p2); // expected-warning{{UNKNOWN}} |
697 | } |
698 | }; |
699 | |
700 | Empty2::Empty2() { |
701 | glob_p1 = static_cast<PairDoubleEmptyContainer *>(this)->p.p1; |
702 | glob_p2 = static_cast<PairDoubleEmptyContainer *>(this)->p.p2; |
703 | } |
704 | |
705 | class PairContainerContainer { |
706 | int padding; |
707 | PairContainer pc; |
708 | public: |
709 | PairContainerContainer() : pc(1) {} |
710 | }; |
711 | } |
712 | |
713 | namespace InitializerList { |
714 | struct List { |
715 | bool usedInitializerList; |
716 | |
717 | List() : usedInitializerList(false) {} |
718 | List(std::initializer_list<int>) : usedInitializerList(true) {} |
719 | }; |
720 | |
721 | void testStatic() { |
722 | List defaultCtor; |
723 | clang_analyzer_eval(!defaultCtor.usedInitializerList); // expected-warning{{TRUE}} |
724 | |
725 | List list{1, 2}; |
726 | clang_analyzer_eval(list.usedInitializerList); // expected-warning{{TRUE}} |
727 | } |
728 | |
729 | void testDynamic() { |
730 | List *list = new List{1, 2}; |
731 | clang_analyzer_eval(list->usedInitializerList); // expected-warning{{TRUE}} |
732 | } |
733 | } |
734 | |
735 | namespace PR19579 { |
736 | class C {}; |
737 | |
738 | void f() { |
739 | C(); |
740 | int a; |
741 | |
742 | extern void use(int); |
743 | use(a); // expected-warning{{uninitialized}} |
744 | } |
745 | |
746 | void g() { |
747 | struct S { |
748 | C c; |
749 | int i; |
750 | }; |
751 | |
752 | // This order triggers the initialization of the inner "a" after the |
753 | // constructor for "C" is run, which used to confuse the analyzer |
754 | // (is "C()" the initialization of "a"?). |
755 | struct S s = { |
756 | C(), |
757 | ({ |
758 | int a, b = 0; |
759 | 0; |
760 | }) |
761 | }; |
762 | } |
763 | } |
764 | |
765 | namespace NoCrashOnEmptyBaseOptimization { |
766 | struct NonEmptyBase { |
767 | int X; |
768 | explicit NonEmptyBase(int X) : X(X) {} |
769 | }; |
770 | |
771 | struct EmptyBase {}; |
772 | |
773 | struct S : NonEmptyBase, EmptyBase { |
774 | S() : NonEmptyBase(0), EmptyBase() {} |
775 | }; |
776 | |
777 | void testSCtorNoCrash() { |
778 | S s; |
779 | } |
780 | } |
781 | |
782 | namespace EmptyBaseAssign { |
783 | struct B1 {}; |
784 | struct B2 { int x; }; |
785 | struct D: public B1, public B2 { |
786 | const D &operator=(const D &d) { |
787 | *((B2 *)this) = d; |
788 | *((B1 *)this) = d; |
789 | return *this; |
790 | } |
791 | }; |
792 | |
793 | void test() { |
794 | D d1; |
795 | d1.x = 1; |
796 | D d2; |
797 | d2 = d1; |
798 | clang_analyzer_eval(d2.x == 1); // expected-warning{{TRUE}} |
799 | } |
800 | } |
801 | |
802 | namespace vbase_zero_init { |
803 | class A { |
804 | virtual void foo(); |
805 | }; |
806 | |
807 | class B { |
808 | virtual void bar(); |
809 | public: |
810 | static int glob_y, glob_z, glob_w; |
811 | int x; |
812 | B(); // Body below. |
813 | }; |
814 | |
815 | class C : virtual public A { |
816 | public: |
817 | int y; |
818 | }; |
819 | |
820 | class D : public B, public C { |
821 | public: |
822 | // 'z', unlike 'w', resides in an area that would have been within padding of |
823 | // base class 'C' if it wasn't part of 'D', but only on 64-bit systems. |
824 | int z, w; |
825 | // Initialization order: A(), B(), C(). |
826 | D() : A(), C() { |
827 | clang_analyzer_eval(x == 1); // expected-warning{{TRUE}} |
828 | clang_analyzer_eval(y == 0); // expected-warning{{TRUE}} |
829 | #ifdef I386 |
830 | clang_analyzer_eval(z == 3); // expected-warning{{TRUE}} |
831 | #else |
832 | // FIXME: Should be TRUE. Initialized in B(). |
833 | clang_analyzer_eval(z == 3); // expected-warning{{UNKNOWN}} |
834 | #endif |
835 | clang_analyzer_eval(w == 4); // expected-warning{{TRUE}} |
836 | |
837 | // FIXME: Should be UNKNOWN. Changed in B() since glob_y was assigned. |
838 | clang_analyzer_eval(y == glob_y); // expected-warning{{TRUE}} |
839 | |
840 | #ifdef I386 |
841 | clang_analyzer_eval(z == glob_z); // expected-warning{{UNKNOWN}} |
842 | #else |
843 | // FIXME: Should be UNKNOWN. Changed in B() since glob_z was assigned. |
844 | clang_analyzer_eval(z == glob_z); // expected-warning{{TRUE}} |
845 | #endif |
846 | |
847 | clang_analyzer_eval(w == glob_w); // expected-warning{{UNKNOWN}} |
848 | } // no-crash |
849 | }; |
850 | |
851 | B::B() : x(1) { |
852 | // Our static members will store the old garbage values of fields that aren't |
853 | // yet initialized. These aren't certainly garbage though (i.e. the |
854 | // constructor could have been called on an initialized piece of memory), |
855 | // so no uninitialized value warning here, and these should be symbols, not |
856 | // undefined values, for later comparison. |
857 | glob_y = static_cast<D *>(this)->y; |
858 | glob_z = static_cast<D *>(this)->z; |
859 | glob_w = static_cast<D *>(this)->w; |
860 | static_cast<D *>(this)->y = 2; |
861 | static_cast<D *>(this)->z = 3; |
862 | static_cast<D *>(this)->w = 4; |
863 | } |
864 | } |
865 | |