1// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config ipa=inlining -analyzer-config c++-allocator-inlining=true -verify %s
2
3void clang_analyzer_eval(bool);
4void clang_analyzer_checkInlined(bool);
5
6typedef __typeof__(sizeof(int)) size_t;
7extern "C" void *malloc(size_t);
8
9// This is the standard placement new.
10inline void* operator new(size_t, void* __p) throw()
11{
12  clang_analyzer_checkInlined(true);// expected-warning{{TRUE}}
13  return __p;
14}
15
16
17class A {
18public:
19  int getZero() { return 0; }
20  virtual int getNum() { return 0; }
21};
22
23void test(A &a) {
24  clang_analyzer_eval(a.getZero() == 0); // expected-warning{{TRUE}}
25  clang_analyzer_eval(a.getNum() == 0); // expected-warning{{UNKNOWN}}
26
27  A copy(a);
28  clang_analyzer_eval(copy.getZero() == 0); // expected-warning{{TRUE}}
29  clang_analyzer_eval(copy.getNum() == 0); // expected-warning{{TRUE}}
30}
31
32
33class One : public A {
34public:
35  virtual int getNum() { return 1; }
36};
37
38void testPathSensitivity(int x) {
39  A a;
40  One b;
41
42  A *ptr;
43  switch (x) {
44  case 0:
45    ptr = &a;
46    break;
47  case 1:
48    ptr = &b;
49    break;
50  default:
51    return;
52  }
53
54  // This should be true on both branches.
55  clang_analyzer_eval(ptr->getNum() == x); // expected-warning {{TRUE}}
56}
57
58
59namespace PureVirtualParent {
60  class Parent {
61  public:
62    virtual int pureVirtual() const = 0;
63    int callVirtual() const {
64      return pureVirtual();
65    }
66  };
67
68  class Child : public Parent {
69  public:
70    virtual int pureVirtual() const {
71      clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
72      return 42;
73    }
74  };
75
76  void testVirtual() {
77    Child x;
78
79    clang_analyzer_eval(x.pureVirtual() == 42); // expected-warning{{TRUE}}
80    clang_analyzer_eval(x.callVirtual() == 42); // expected-warning{{TRUE}}
81  }
82}
83
84
85namespace PR13569 {
86  class Parent {
87  protected:
88    int m_parent;
89    virtual int impl() const = 0;
90
91    Parent() : m_parent(0) {}
92
93  public:
94    int interface() const {
95      clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
96      return impl();
97    }
98  };
99
100  class Child : public Parent {
101  protected:
102    virtual int impl() const {
103      clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
104      return m_parent + m_child;
105    }
106
107  public:
108    Child() : m_child(0) {}
109
110    int m_child;
111  };
112
113  void testVirtual() {
114    Child x;
115    x.m_child = 42;
116
117    // Don't crash when inlining and devirtualizing.
118    x.interface();
119  }
120
121
122  class Grandchild : public Child {};
123
124  void testDevirtualizeToMiddle() {
125    Grandchild x;
126    x.m_child = 42;
127
128    // Don't crash when inlining and devirtualizing.
129    x.interface();
130  }
131}
132
133namespace PR13569_virtual {
134  class Parent {
135  protected:
136    int m_parent;
137    virtual int impl() const = 0;
138
139    Parent() : m_parent(0) {}
140
141  public:
142    int interface() const {
143      clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
144      return impl();
145    }
146  };
147
148  class Child : virtual public Parent {
149  protected:
150    virtual int impl() const {
151      clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
152      return m_parent + m_child;
153    }
154
155  public:
156    Child() : m_child(0) {}
157
158    int m_child;
159  };
160
161  void testVirtual() {
162    Child x;
163    x.m_child = 42;
164
165    // Don't crash when inlining and devirtualizing.
166    x.interface();
167  }
168
169
170  class Grandchild : virtual public Child {};
171
172  void testDevirtualizeToMiddle() {
173    Grandchild x;
174    x.m_child = 42;
175
176    // Don't crash when inlining and devirtualizing.
177    x.interface();
178  }
179}
180
181namespace Invalidation {
182  struct X {
183    void touch(int &x) const {
184      x = 0;
185    }
186
187    void touch2(int &x) const;
188
189    virtual void touchV(int &x) const {
190      x = 0;
191    }
192
193    virtual void touchV2(int &x) const;
194
195    int test() const {
196      // We were accidentally not invalidating under inlining
197      // at one point for virtual methods with visible definitions.
198      int a, b, c, d;
199      touch(a);
200      touch2(b);
201      touchV(c);
202      touchV2(d);
203      return a + b + c + d; // no-warning
204    }
205  };
206}
207
208namespace DefaultArgs {
209  int takesDefaultArgs(int i = 42) {
210    return -i;
211  }
212
213  void testFunction() {
214    clang_analyzer_eval(takesDefaultArgs(1) == -1); // expected-warning{{TRUE}}
215    clang_analyzer_eval(takesDefaultArgs() == -42); // expected-warning{{TRUE}}
216  }
217
218  class Secret {
219  public:
220    static const int value = 40 + 2;
221    int get(int i = value) {
222      return i;
223    }
224  };
225
226  void testMethod() {
227    Secret obj;
228    clang_analyzer_eval(obj.get(1) == 1); // expected-warning{{TRUE}}
229    clang_analyzer_eval(obj.get() == 42); // expected-warning{{TRUE}}
230    clang_analyzer_eval(Secret::value == 42); // expected-warning{{TRUE}}
231  }
232
233  enum ABC {
234    A = 0,
235    B = 1,
236    C = 2
237  };
238
239  int enumUser(ABC input = B) {
240    return static_cast<int>(input);
241  }
242
243  void testEnum() {
244    clang_analyzer_eval(enumUser(C) == 2); // expected-warning{{TRUE}}
245    clang_analyzer_eval(enumUser() == 1); // expected-warning{{TRUE}}
246  }
247
248
249  int exprUser(int input = 2 * 4) {
250    return input;
251  }
252
253  int complicatedExprUser(int input = 2 * Secret::value) {
254    return input;
255  }
256
257  void testExprs() {
258    clang_analyzer_eval(exprUser(1) == 1); // expected-warning{{TRUE}}
259    clang_analyzer_eval(exprUser() == 8); // expected-warning{{TRUE}}
260
261    clang_analyzer_eval(complicatedExprUser(1) == 1); // expected-warning{{TRUE}}
262    clang_analyzer_eval(complicatedExprUser() == 84); // expected-warning{{TRUE}}
263  }
264
265  int defaultReference(const int &input = 42) {
266    return -input;
267  }
268  int defaultReferenceZero(const int &input = 0) {
269    return -input;
270  }
271
272  void testReference() {
273    clang_analyzer_eval(defaultReference(1) == -1); // expected-warning{{TRUE}}
274    clang_analyzer_eval(defaultReference() == -42); // expected-warning{{TRUE}}
275
276    clang_analyzer_eval(defaultReferenceZero(1) == -1); // expected-warning{{TRUE}}
277    clang_analyzer_eval(defaultReferenceZero() == 0); // expected-warning{{TRUE}}
278}
279
280  double defaultFloatReference(const double &i = 42) {
281    return -i;
282  }
283  double defaultFloatReferenceZero(const double &i = 0) {
284    return -i;
285  }
286
287  void testFloatReference() {
288    clang_analyzer_eval(defaultFloatReference(1) == -1); // expected-warning{{UNKNOWN}}
289    clang_analyzer_eval(defaultFloatReference() == -42); // expected-warning{{UNKNOWN}}
290
291    clang_analyzer_eval(defaultFloatReferenceZero(1) == -1); // expected-warning{{UNKNOWN}}
292    clang_analyzer_eval(defaultFloatReferenceZero() == 0); // expected-warning{{UNKNOWN}}
293  }
294
295  char defaultString(const char *s = "abc") {
296    return s[1];
297  }
298
299  void testString() {
300    clang_analyzer_eval(defaultString("xyz") == 'y'); // expected-warning{{TRUE}}
301    clang_analyzer_eval(defaultString() == 'b'); // expected-warning{{TRUE}}
302  }
303}
304
305namespace OperatorNew {
306  class IntWrapper {
307  public:
308    int value;
309
310    IntWrapper(int input) : value(input) {
311      // We don't want this constructor to be inlined unless we can actually
312      // use the proper region for operator new.
313      // See PR12014 and <rdar://problem/12180598>.
314      clang_analyzer_checkInlined(false); // no-warning
315    }
316  };
317
318  void test() {
319    IntWrapper *obj = new IntWrapper(42);
320    // should be TRUE
321    clang_analyzer_eval(obj->value == 42); // expected-warning{{UNKNOWN}}
322    delete obj;
323  }
324
325  void testPlacement() {
326    IntWrapper *obj = static_cast<IntWrapper *>(malloc(sizeof(IntWrapper)));
327    IntWrapper *alias = new (obj) IntWrapper(42);
328
329    clang_analyzer_eval(alias == obj); // expected-warning{{TRUE}}
330
331    // should be TRUE
332    clang_analyzer_eval(obj->value == 42); // expected-warning{{UNKNOWN}}
333  }
334}
335
336
337namespace VirtualWithSisterCasts {
338  // This entire set of tests exercises casts from sister classes and
339  // from classes outside the hierarchy, which can very much confuse
340  // code that uses DynamicTypeInfo or needs to construct CXXBaseObjectRegions.
341  // These examples used to cause crashes in +Asserts builds.
342  struct Parent {
343    virtual int foo();
344    int x;
345  };
346
347  struct A : Parent {
348    virtual int foo() { return 42; }
349  };
350
351  struct B : Parent {
352    virtual int foo();
353  };
354
355  struct Grandchild : public A {};
356
357  struct Unrelated {};
358
359  void testDowncast(Parent *b) {
360    A *a = (A *)(void *)b;
361    clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}}
362
363    a->x = 42;
364    clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}}
365  }
366
367  void testRelated(B *b) {
368    A *a = (A *)(void *)b;
369    clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}}
370
371    a->x = 42;
372    clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}}
373  }
374
375  void testUnrelated(Unrelated *b) {
376    A *a = (A *)(void *)b;
377    clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}}
378
379    a->x = 42;
380    clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}}
381  }
382
383  void testCastViaNew(B *b) {
384    Grandchild *g = new (b) Grandchild();
385    clang_analyzer_eval(g->foo() == 42); // expected-warning{{TRUE}}
386
387    g->x = 42;
388    clang_analyzer_eval(g->x == 42); // expected-warning{{TRUE}}
389  }
390}
391
392
393namespace QualifiedCalls {
394  void test(One *object) {
395    // This uses the One class from the top of the file.
396    clang_analyzer_eval(object->getNum() == 1); // expected-warning{{UNKNOWN}}
397    clang_analyzer_eval(object->One::getNum() == 1); // expected-warning{{TRUE}}
398    clang_analyzer_eval(object->A::getNum() == 0); // expected-warning{{TRUE}}
399
400    // getZero is non-virtual.
401    clang_analyzer_eval(object->getZero() == 0); // expected-warning{{TRUE}}
402    clang_analyzer_eval(object->One::getZero() == 0); // expected-warning{{TRUE}}
403    clang_analyzer_eval(object->A::getZero() == 0); // expected-warning{{TRUE}}
404}
405}
406
407
408namespace rdar12409977  {
409  struct Base {
410    int x;
411  };
412
413  struct Parent : public Base {
414    virtual Parent *vGetThis();
415    Parent *getThis() { return vGetThis(); }
416  };
417
418  struct Child : public Parent {
419    virtual Child *vGetThis() { return this; }
420  };
421
422  void test() {
423    Child obj;
424    obj.x = 42;
425
426    // Originally, calling a devirtualized method with a covariant return type
427    // caused a crash because the return value had the wrong type. When we then
428    // go to layer a CXXBaseObjectRegion on it, the base isn't a direct base of
429    // the object region and we get an assertion failure.
430    clang_analyzer_eval(obj.getThis()->x == 42); // expected-warning{{TRUE}}
431  }
432}
433
434namespace bug16307 {
435  void one_argument(int a) { }
436  void call_with_less() {
437    reinterpret_cast<void (*)()>(one_argument)(); // expected-warning{{Function taking 1 argument}}
438  }
439}
440