1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config ipa=inlining -analyzer-config c++-allocator-inlining=true -verify -analyzer-config eagerly-assume=false %s |
2 | |
3 | void clang_analyzer_eval(bool); |
4 | void clang_analyzer_checkInlined(bool); |
5 | |
6 | typedef __typeof__(sizeof(int)) size_t; |
7 | extern "C" void *malloc(size_t); |
8 | |
9 | // This is the standard placement new. |
10 | inline void* operator new(size_t, void* __p) throw() |
11 | { |
12 | clang_analyzer_checkInlined(true);// expected-warning{{TRUE}} |
13 | return __p; |
14 | } |
15 | |
16 | |
17 | class A { |
18 | public: |
19 | int getZero() { return 0; } |
20 | virtual int getNum() { return 0; } |
21 | }; |
22 | |
23 | void 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 | |
33 | class One : public A { |
34 | public: |
35 | virtual int getNum() { return 1; } |
36 | }; |
37 | |
38 | void 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 | |
59 | namespace 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 | |
85 | namespace 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 | |
133 | namespace 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 | |
181 | namespace 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 | |
208 | namespace 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 | const void * const void_string = "abc"; |
305 | |
306 | void testBitcastedString() { |
307 | clang_analyzer_eval(0 != void_string); // expected-warning{{TRUE}} |
308 | clang_analyzer_eval('b' == ((char *)void_string)[1]); // expected-warning{{TRUE}} |
309 | } |
310 | } |
311 | |
312 | namespace OperatorNew { |
313 | class IntWrapper { |
314 | public: |
315 | int value; |
316 | |
317 | IntWrapper(int input) : value(input) { |
318 | clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} |
319 | } |
320 | }; |
321 | |
322 | void test() { |
323 | IntWrapper *obj = new IntWrapper(42); |
324 | clang_analyzer_eval(obj->value == 42); // expected-warning{{TRUE}} |
325 | delete obj; |
326 | } |
327 | |
328 | void testPlacement() { |
329 | IntWrapper *obj = static_cast<IntWrapper *>(malloc(sizeof(IntWrapper))); |
330 | IntWrapper *alias = new (obj) IntWrapper(42); |
331 | |
332 | clang_analyzer_eval(alias == obj); // expected-warning{{TRUE}} |
333 | |
334 | clang_analyzer_eval(obj->value == 42); // expected-warning{{TRUE}} |
335 | // Because malloc() was never free()d: |
336 | // expected-warning@-2{{Potential leak of memory pointed to by 'alias'}} |
337 | } |
338 | } |
339 | |
340 | |
341 | namespace VirtualWithSisterCasts { |
342 | // This entire set of tests exercises casts from sister classes and |
343 | // from classes outside the hierarchy, which can very much confuse |
344 | // code that uses DynamicTypeInfo or needs to construct CXXBaseObjectRegions. |
345 | // These examples used to cause crashes in +Asserts builds. |
346 | struct Parent { |
347 | virtual int foo(); |
348 | int x; |
349 | }; |
350 | |
351 | struct A : Parent { |
352 | virtual int foo() { return 42; } |
353 | }; |
354 | |
355 | struct B : Parent { |
356 | virtual int foo(); |
357 | }; |
358 | |
359 | struct Grandchild : public A {}; |
360 | |
361 | struct Unrelated {}; |
362 | |
363 | void testDowncast(Parent *b) { |
364 | A *a = (A *)(void *)b; |
365 | clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}} |
366 | |
367 | a->x = 42; |
368 | clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}} |
369 | } |
370 | |
371 | void testRelated(B *b) { |
372 | A *a = (A *)(void *)b; |
373 | clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}} |
374 | |
375 | a->x = 42; |
376 | clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}} |
377 | } |
378 | |
379 | void testUnrelated(Unrelated *b) { |
380 | A *a = (A *)(void *)b; |
381 | clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}} |
382 | |
383 | a->x = 42; |
384 | clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}} |
385 | } |
386 | |
387 | void testCastViaNew(B *b) { |
388 | Grandchild *g = new (b) Grandchild(); |
389 | clang_analyzer_eval(g->foo() == 42); // expected-warning{{TRUE}} |
390 | |
391 | g->x = 42; |
392 | clang_analyzer_eval(g->x == 42); // expected-warning{{TRUE}} |
393 | } |
394 | } |
395 | |
396 | |
397 | namespace QualifiedCalls { |
398 | void test(One *object) { |
399 | // This uses the One class from the top of the file. |
400 | clang_analyzer_eval(object->getNum() == 1); // expected-warning{{UNKNOWN}} |
401 | clang_analyzer_eval(object->One::getNum() == 1); // expected-warning{{TRUE}} |
402 | clang_analyzer_eval(object->A::getNum() == 0); // expected-warning{{TRUE}} |
403 | |
404 | // getZero is non-virtual. |
405 | clang_analyzer_eval(object->getZero() == 0); // expected-warning{{TRUE}} |
406 | clang_analyzer_eval(object->One::getZero() == 0); // expected-warning{{TRUE}} |
407 | clang_analyzer_eval(object->A::getZero() == 0); // expected-warning{{TRUE}} |
408 | } |
409 | } |
410 | |
411 | |
412 | namespace rdar12409977 { |
413 | struct Base { |
414 | int x; |
415 | }; |
416 | |
417 | struct Parent : public Base { |
418 | virtual Parent *vGetThis(); |
419 | Parent *getThis() { return vGetThis(); } |
420 | }; |
421 | |
422 | struct Child : public Parent { |
423 | virtual Child *vGetThis() { return this; } |
424 | }; |
425 | |
426 | void test() { |
427 | Child obj; |
428 | obj.x = 42; |
429 | |
430 | // Originally, calling a devirtualized method with a covariant return type |
431 | // caused a crash because the return value had the wrong type. When we then |
432 | // go to layer a CXXBaseObjectRegion on it, the base isn't a direct base of |
433 | // the object region and we get an assertion failure. |
434 | clang_analyzer_eval(obj.getThis()->x == 42); // expected-warning{{TRUE}} |
435 | } |
436 | } |
437 | |
438 | namespace bug16307 { |
439 | void one_argument(int a) { } |
440 | void call_with_less() { |
441 | reinterpret_cast<void (*)()>(one_argument)(); // expected-warning{{Function taking 1 argument is called with fewer (0)}} |
442 | } |
443 | } |
444 | |