ctor.mm revision 98123284826bb4ce422775563ff1a01580ec5766
1// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify %s
2
3void clang_analyzer_eval(bool);
4void clang_analyzer_checkInlined(bool);
5
6// A simplified version of std::move.
7template <typename T>
8T &&move(T &obj) {
9  return static_cast<T &&>(obj);
10}
11
12
13struct Wrapper {
14  __strong id obj;
15};
16
17void test() {
18  Wrapper w;
19  // force a diagnostic
20  *(char *)0 = 1; // expected-warning{{Dereference of null pointer}}
21}
22
23
24struct IntWrapper {
25  int x;
26};
27
28void testCopyConstructor() {
29  IntWrapper a;
30  a.x = 42;
31
32  IntWrapper b(a);
33  clang_analyzer_eval(b.x == 42); // expected-warning{{TRUE}}
34}
35
36struct NonPODIntWrapper {
37  int x;
38
39  virtual int get();
40};
41
42void testNonPODCopyConstructor() {
43  NonPODIntWrapper a;
44  a.x = 42;
45
46  NonPODIntWrapper b(a);
47  clang_analyzer_eval(b.x == 42); // expected-warning{{TRUE}}
48}
49
50
51namespace ConstructorVirtualCalls {
52  class A {
53  public:
54    int *out1, *out2, *out3;
55
56    virtual int get() { return 1; }
57
58    A(int *out1) {
59      *out1 = get();
60    }
61  };
62
63  class B : public A {
64  public:
65    virtual int get() { return 2; }
66
67    B(int *out1, int *out2) : A(out1) {
68      *out2 = get();
69    }
70  };
71
72  class C : public B {
73  public:
74    virtual int get() { return 3; }
75
76    C(int *out1, int *out2, int *out3) : B(out1, out2) {
77      *out3 = get();
78    }
79  };
80
81  void test() {
82    int a, b, c;
83
84    C obj(&a, &b, &c);
85    clang_analyzer_eval(a == 1); // expected-warning{{TRUE}}
86    clang_analyzer_eval(b == 2); // expected-warning{{TRUE}}
87    clang_analyzer_eval(c == 3); // expected-warning{{TRUE}}
88
89    clang_analyzer_eval(obj.get() == 3); // expected-warning{{TRUE}}
90
91    // Sanity check for devirtualization.
92    A *base = &obj;
93    clang_analyzer_eval(base->get() == 3); // expected-warning{{TRUE}}
94  }
95}
96
97namespace TemporaryConstructor {
98  class BoolWrapper {
99  public:
100    BoolWrapper() {
101      clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
102      value = true;
103    }
104    bool value;
105  };
106
107  void test() {
108    // PR13717 - Don't crash when a CXXTemporaryObjectExpr is inlined.
109    if (BoolWrapper().value)
110      return;
111  }
112}
113
114
115namespace ConstructorUsedAsRValue {
116  using TemporaryConstructor::BoolWrapper;
117
118  bool extractValue(BoolWrapper b) {
119    return b.value;
120  }
121
122  void test() {
123    bool result = extractValue(BoolWrapper());
124    clang_analyzer_eval(result); // expected-warning{{TRUE}}
125  }
126}
127
128namespace PODUninitialized {
129  class POD {
130  public:
131    int x, y;
132  };
133
134  class PODWrapper {
135  public:
136    POD p;
137  };
138
139  class NonPOD {
140  public:
141    int x, y;
142
143    NonPOD() {}
144    NonPOD(const NonPOD &Other)
145      : x(Other.x), y(Other.y) // expected-warning {{undefined}}
146    {
147    }
148    NonPOD(NonPOD &&Other)
149    : x(Other.x), y(Other.y) // expected-warning {{undefined}}
150    {
151    }
152
153    NonPOD &operator=(const NonPOD &Other)
154    {
155      x = Other.x;
156      y = Other.y; // expected-warning {{undefined}}
157      return *this;
158    }
159    NonPOD &operator=(NonPOD &&Other)
160    {
161      x = Other.x;
162      y = Other.y; // expected-warning {{undefined}}
163      return *this;
164    }
165  };
166
167  class NonPODWrapper {
168  public:
169    class Inner {
170    public:
171      int x, y;
172
173      Inner() {}
174      Inner(const Inner &Other)
175        : x(Other.x), y(Other.y) // expected-warning {{undefined}}
176      {
177      }
178      Inner(Inner &&Other)
179      : x(Other.x), y(Other.y) // expected-warning {{undefined}}
180      {
181      }
182
183      Inner &operator=(const Inner &Other)
184      {
185        x = Other.x; // expected-warning {{undefined}}
186        y = Other.y;
187        return *this;
188      }
189      Inner &operator=(Inner &&Other)
190      {
191        x = Other.x; // expected-warning {{undefined}}
192        y = Other.y;
193        return *this;
194      }
195    };
196
197    Inner p;
198  };
199
200  void testPOD() {
201    POD p;
202    p.x = 1;
203    POD p2 = p; // no-warning
204    clang_analyzer_eval(p2.x == 1); // expected-warning{{TRUE}}
205    POD p3 = move(p); // no-warning
206    clang_analyzer_eval(p3.x == 1); // expected-warning{{TRUE}}
207
208    // Use rvalues as well.
209    clang_analyzer_eval(POD(p3).x == 1); // expected-warning{{TRUE}}
210
211    PODWrapper w;
212    w.p.y = 1;
213    PODWrapper w2 = w; // no-warning
214    clang_analyzer_eval(w2.p.y == 1); // expected-warning{{TRUE}}
215    PODWrapper w3 = move(w); // no-warning
216    clang_analyzer_eval(w3.p.y == 1); // expected-warning{{TRUE}}
217
218    // Use rvalues as well.
219    clang_analyzer_eval(PODWrapper(w3).p.y == 1); // expected-warning{{TRUE}}
220  }
221
222  void testNonPOD() {
223    NonPOD p;
224    p.x = 1;
225    NonPOD p2 = p;
226  }
227
228  void testNonPODMove() {
229    NonPOD p;
230    p.x = 1;
231    NonPOD p2 = move(p);
232  }
233
234  void testNonPODWrapper() {
235    NonPODWrapper w;
236    w.p.y = 1;
237    NonPODWrapper w2 = w;
238  }
239
240  void testNonPODWrapperMove() {
241    NonPODWrapper w;
242    w.p.y = 1;
243    NonPODWrapper w2 = move(w);
244  }
245
246  // Not strictly about constructors, but trivial assignment operators should
247  // essentially work the same way.
248  namespace AssignmentOperator {
249    void testPOD() {
250      POD p;
251      p.x = 1;
252      POD p2;
253      p2 = p; // no-warning
254      clang_analyzer_eval(p2.x == 1); // expected-warning{{TRUE}}
255      POD p3;
256      p3 = move(p); // no-warning
257      clang_analyzer_eval(p3.x == 1); // expected-warning{{TRUE}}
258
259      PODWrapper w;
260      w.p.y = 1;
261      PODWrapper w2;
262      w2 = w; // no-warning
263      clang_analyzer_eval(w2.p.y == 1); // expected-warning{{TRUE}}
264      PODWrapper w3;
265      w3 = move(w); // no-warning
266      clang_analyzer_eval(w3.p.y == 1); // expected-warning{{TRUE}}
267    }
268
269    void testReturnValue() {
270      POD p;
271      p.x = 1;
272      POD p2;
273      clang_analyzer_eval(&(p2 = p) == &p2); // expected-warning{{TRUE}}
274
275      PODWrapper w;
276      w.p.y = 1;
277      PODWrapper w2;
278      clang_analyzer_eval(&(w2 = w) == &w2); // expected-warning{{TRUE}}
279    }
280
281    void testNonPOD() {
282      NonPOD p;
283      p.x = 1;
284      NonPOD p2;
285      p2 = p;
286    }
287
288    void testNonPODMove() {
289      NonPOD p;
290      p.x = 1;
291      NonPOD p2;
292      p2 = move(p);
293    }
294
295    void testNonPODWrapper() {
296      NonPODWrapper w;
297      w.p.y = 1;
298      NonPODWrapper w2;
299      w2 = w;
300    }
301
302    void testNonPODWrapperMove() {
303      NonPODWrapper w;
304      w.p.y = 1;
305      NonPODWrapper w2;
306      w2 = move(w);
307    }
308  }
309}
310
311namespace ArrayMembers {
312  struct Primitive {
313    int values[3];
314  };
315
316  void testPrimitive() {
317    Primitive a = { { 1, 2, 3 } };
318
319    clang_analyzer_eval(a.values[0] == 1); // expected-warning{{TRUE}}
320    clang_analyzer_eval(a.values[1] == 2); // expected-warning{{TRUE}}
321    clang_analyzer_eval(a.values[2] == 3); // expected-warning{{TRUE}}
322
323    Primitive b = a;
324
325    clang_analyzer_eval(b.values[0] == 1); // expected-warning{{TRUE}}
326    clang_analyzer_eval(b.values[1] == 2); // expected-warning{{TRUE}}
327    clang_analyzer_eval(b.values[2] == 3); // expected-warning{{TRUE}}
328
329    Primitive c;
330    c = b;
331
332    clang_analyzer_eval(c.values[0] == 1); // expected-warning{{TRUE}}
333    clang_analyzer_eval(c.values[1] == 2); // expected-warning{{TRUE}}
334    clang_analyzer_eval(c.values[2] == 3); // expected-warning{{TRUE}}
335  }
336
337  struct NestedPrimitive {
338    int values[2][3];
339  };
340
341  void testNestedPrimitive() {
342    NestedPrimitive a = { { { 0, 0, 0 }, { 1, 2, 3 } } };
343
344    clang_analyzer_eval(a.values[1][0] == 1); // expected-warning{{TRUE}}
345    clang_analyzer_eval(a.values[1][1] == 2); // expected-warning{{TRUE}}
346    clang_analyzer_eval(a.values[1][2] == 3); // expected-warning{{TRUE}}
347
348    NestedPrimitive b = a;
349
350    clang_analyzer_eval(b.values[1][0] == 1); // expected-warning{{TRUE}}
351    clang_analyzer_eval(b.values[1][1] == 2); // expected-warning{{TRUE}}
352    clang_analyzer_eval(b.values[1][2] == 3); // expected-warning{{TRUE}}
353
354    NestedPrimitive c;
355    c = b;
356
357    clang_analyzer_eval(c.values[1][0] == 1); // expected-warning{{TRUE}}
358    clang_analyzer_eval(c.values[1][1] == 2); // expected-warning{{TRUE}}
359    clang_analyzer_eval(c.values[1][2] == 3); // expected-warning{{TRUE}}
360  }
361
362  struct POD {
363    IntWrapper values[3];
364  };
365
366  void testPOD() {
367    POD a = { { { 1 }, { 2 }, { 3 } } };
368
369    clang_analyzer_eval(a.values[0].x == 1); // expected-warning{{TRUE}}
370    clang_analyzer_eval(a.values[1].x == 2); // expected-warning{{TRUE}}
371    clang_analyzer_eval(a.values[2].x == 3); // expected-warning{{TRUE}}
372
373    POD b = a;
374
375    clang_analyzer_eval(b.values[0].x == 1); // expected-warning{{TRUE}}
376    clang_analyzer_eval(b.values[1].x == 2); // expected-warning{{TRUE}}
377    clang_analyzer_eval(b.values[2].x == 3); // expected-warning{{TRUE}}
378
379    POD c;
380    c = b;
381
382    clang_analyzer_eval(c.values[0].x == 1); // expected-warning{{TRUE}}
383    clang_analyzer_eval(c.values[1].x == 2); // expected-warning{{TRUE}}
384    clang_analyzer_eval(c.values[2].x == 3); // expected-warning{{TRUE}}
385  }
386
387  struct NestedPOD {
388    IntWrapper values[2][3];
389  };
390
391  void testNestedPOD() {
392    NestedPOD a = { { { { 0 }, { 0 }, { 0 } }, { { 1 }, { 2 }, { 3 } } } };
393
394    clang_analyzer_eval(a.values[1][0].x == 1); // expected-warning{{TRUE}}
395    clang_analyzer_eval(a.values[1][1].x == 2); // expected-warning{{TRUE}}
396    clang_analyzer_eval(a.values[1][2].x == 3); // expected-warning{{TRUE}}
397
398    NestedPOD b = a;
399
400    clang_analyzer_eval(b.values[1][0].x == 1); // expected-warning{{TRUE}}
401    clang_analyzer_eval(b.values[1][1].x == 2); // expected-warning{{TRUE}}
402    clang_analyzer_eval(b.values[1][2].x == 3); // expected-warning{{TRUE}}
403
404    NestedPOD c;
405    c = b;
406
407    clang_analyzer_eval(c.values[1][0].x == 1); // expected-warning{{TRUE}}
408    clang_analyzer_eval(c.values[1][1].x == 2); // expected-warning{{TRUE}}
409    clang_analyzer_eval(c.values[1][2].x == 3); // expected-warning{{TRUE}}
410  }
411
412  struct NonPOD {
413    NonPODIntWrapper values[3];
414  };
415
416  void testNonPOD() {
417    NonPOD a;
418    a.values[0].x = 1;
419    a.values[1].x = 2;
420    a.values[2].x = 3;
421
422    clang_analyzer_eval(a.values[0].x == 1); // expected-warning{{TRUE}}
423    clang_analyzer_eval(a.values[1].x == 2); // expected-warning{{TRUE}}
424    clang_analyzer_eval(a.values[2].x == 3); // expected-warning{{TRUE}}
425
426    NonPOD b = a;
427
428    clang_analyzer_eval(b.values[0].x == 1); // expected-warning{{UNKNOWN}}
429    clang_analyzer_eval(b.values[1].x == 2); // expected-warning{{UNKNOWN}}
430    clang_analyzer_eval(b.values[2].x == 3); // expected-warning{{UNKNOWN}}
431
432    NonPOD c;
433    c = b;
434
435    clang_analyzer_eval(c.values[0].x == 1); // expected-warning{{UNKNOWN}}
436    clang_analyzer_eval(c.values[1].x == 2); // expected-warning{{UNKNOWN}}
437    clang_analyzer_eval(c.values[2].x == 3); // expected-warning{{UNKNOWN}}
438  }
439
440  struct NestedNonPOD {
441    NonPODIntWrapper values[2][3];
442  };
443
444  void testNestedNonPOD() {
445    NestedNonPOD a;
446    a.values[0][0].x = 0;
447    a.values[0][1].x = 0;
448    a.values[0][2].x = 0;
449    a.values[1][0].x = 1;
450    a.values[1][1].x = 2;
451    a.values[1][2].x = 3;
452
453    clang_analyzer_eval(a.values[1][0].x == 1); // expected-warning{{TRUE}}
454    clang_analyzer_eval(a.values[1][1].x == 2); // expected-warning{{TRUE}}
455    clang_analyzer_eval(a.values[1][2].x == 3); // expected-warning{{TRUE}}
456
457    NestedNonPOD b = a;
458
459    clang_analyzer_eval(b.values[1][0].x == 1); // expected-warning{{UNKNOWN}}
460    clang_analyzer_eval(b.values[1][1].x == 2); // expected-warning{{UNKNOWN}}
461    clang_analyzer_eval(b.values[1][2].x == 3); // expected-warning{{UNKNOWN}}
462
463    NestedNonPOD c;
464    c = b;
465
466    clang_analyzer_eval(c.values[1][0].x == 1); // expected-warning{{UNKNOWN}}
467    clang_analyzer_eval(c.values[1][1].x == 2); // expected-warning{{UNKNOWN}}
468    clang_analyzer_eval(c.values[1][2].x == 3); // expected-warning{{UNKNOWN}}
469  }
470  
471  struct NonPODDefaulted {
472    NonPODIntWrapper values[3];
473
474    NonPODDefaulted() = default;
475    NonPODDefaulted(const NonPODDefaulted &) = default;
476    NonPODDefaulted &operator=(const NonPODDefaulted &) = default;
477  };
478
479  void testNonPODDefaulted() {
480    NonPODDefaulted a;
481    a.values[0].x = 1;
482    a.values[1].x = 2;
483    a.values[2].x = 3;
484
485    clang_analyzer_eval(a.values[0].x == 1); // expected-warning{{TRUE}}
486    clang_analyzer_eval(a.values[1].x == 2); // expected-warning{{TRUE}}
487    clang_analyzer_eval(a.values[2].x == 3); // expected-warning{{TRUE}}
488
489    NonPODDefaulted b = a;
490
491    clang_analyzer_eval(b.values[0].x == 1); // expected-warning{{UNKNOWN}}
492    clang_analyzer_eval(b.values[1].x == 2); // expected-warning{{UNKNOWN}}
493    clang_analyzer_eval(b.values[2].x == 3); // expected-warning{{UNKNOWN}}
494
495    NonPODDefaulted c;
496    c = b;
497
498    clang_analyzer_eval(c.values[0].x == 1); // expected-warning{{UNKNOWN}}
499    clang_analyzer_eval(c.values[1].x == 2); // expected-warning{{UNKNOWN}}
500    clang_analyzer_eval(c.values[2].x == 3); // expected-warning{{UNKNOWN}}
501  }
502};
503
504namespace ZeroInitialization {
505  struct raw_pair {
506    int p1;
507    int p2;
508  };
509
510  void testVarDecl() {
511    raw_pair p{};
512    clang_analyzer_eval(p.p1 == 0); // expected-warning{{TRUE}}
513    clang_analyzer_eval(p.p2 == 0); // expected-warning{{TRUE}}
514  }
515
516  void testTemporary() {
517    clang_analyzer_eval(raw_pair().p1 == 0); // expected-warning{{TRUE}}
518    clang_analyzer_eval(raw_pair().p2 == 0); // expected-warning{{TRUE}}
519  }
520
521  void testArray() {
522    raw_pair p[2] = {};
523    clang_analyzer_eval(p[0].p1 == 0); // expected-warning{{TRUE}}
524    clang_analyzer_eval(p[0].p2 == 0); // expected-warning{{TRUE}}
525    clang_analyzer_eval(p[1].p1 == 0); // expected-warning{{TRUE}}
526    clang_analyzer_eval(p[1].p2 == 0); // expected-warning{{TRUE}}
527  }
528
529  void testNew() {
530    // FIXME: Pending proper implementation of constructors for 'new'.
531    raw_pair *pp = new raw_pair();
532    clang_analyzer_eval(pp->p1 == 0); // expected-warning{{UNKNOWN}}
533    clang_analyzer_eval(pp->p2 == 0); // expected-warning{{UNKNOWN}}
534  }
535
536  void testArrayNew() {
537    // FIXME: Pending proper implementation of constructors for 'new[]'.
538    raw_pair *p = new raw_pair[2]();
539    clang_analyzer_eval(p[0].p1 == 0); // expected-warning{{UNKNOWN}}
540    clang_analyzer_eval(p[0].p2 == 0); // expected-warning{{UNKNOWN}}
541    clang_analyzer_eval(p[1].p1 == 0); // expected-warning{{UNKNOWN}}
542    clang_analyzer_eval(p[1].p2 == 0); // expected-warning{{UNKNOWN}}
543  }
544
545  struct initializing_pair {
546  public:
547    int x;
548    raw_pair y;
549    initializing_pair() : x(), y() {}
550  };
551  
552  void testFieldInitializers() {
553    initializing_pair p;
554    clang_analyzer_eval(p.x == 0); // expected-warning{{TRUE}}
555    clang_analyzer_eval(p.y.p1 == 0); // expected-warning{{TRUE}}
556    clang_analyzer_eval(p.y.p2 == 0); // expected-warning{{TRUE}}
557  }
558
559  struct subclass : public raw_pair {
560    subclass() = default;
561  };
562
563  void testSubclass() {
564    subclass p;
565    clang_analyzer_eval(p.p1 == 0); // expected-warning{{garbage}}
566  }
567
568  struct initializing_subclass : public raw_pair {
569    initializing_subclass() : raw_pair() {}
570  };
571
572  void testInitializingSubclass() {
573    initializing_subclass p;
574    clang_analyzer_eval(p.p1 == 0); // expected-warning{{TRUE}}
575    clang_analyzer_eval(p.p2 == 0); // expected-warning{{TRUE}}
576  }
577}
578