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