blob: bc74130b2fdf2e018b01ec2b80dff7a65da263b5 [file] [log] [blame]
Dominic Chen184c6242017-03-03 18:02:02 +00001// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection,cplusplus -analyzer-config c++-inlining=destructors,cfg-temporary-dtors=true -Wno-null-dereference -Wno-inaccessible-base -verify %s
Jordan Rose20edae82012-07-26 20:04:25 +00002
3void clang_analyzer_eval(bool);
Jordan Rose2be6e302012-08-28 20:52:13 +00004void clang_analyzer_checkInlined(bool);
Zhongxing Xu2c966712010-11-20 06:53:12 +00005
6class A {
7public:
8 ~A() {
9 int *x = 0;
10 *x = 3; // expected-warning{{Dereference of null pointer}}
11 }
12};
13
14int main() {
15 A a;
16}
Jordan Rosec5d85242012-07-26 20:04:00 +000017
18
19typedef __typeof(sizeof(int)) size_t;
20void *malloc(size_t);
21void free(void *);
22
23class SmartPointer {
24 void *X;
25public:
26 SmartPointer(void *x) : X(x) {}
27 ~SmartPointer() {
28 free(X);
29 }
30};
31
32void testSmartPointer() {
33 char *mem = (char*)malloc(4);
34 {
35 SmartPointer Deleter(mem);
36 // destructor called here
37 }
38 *mem = 0; // expected-warning{{Use of memory after it is freed}}
39}
Jordan Rosea4c0d212012-07-26 20:04:05 +000040
41
42void doSomething();
43void testSmartPointer2() {
44 char *mem = (char*)malloc(4);
45 {
46 SmartPointer Deleter(mem);
47 // Remove dead bindings...
48 doSomething();
49 // destructor called here
50 }
51 *mem = 0; // expected-warning{{Use of memory after it is freed}}
52}
53
54
55class Subclass : public SmartPointer {
56public:
57 Subclass(void *x) : SmartPointer(x) {}
58};
59
60void testSubclassSmartPointer() {
61 char *mem = (char*)malloc(4);
62 {
63 Subclass Deleter(mem);
64 // Remove dead bindings...
65 doSomething();
66 // destructor called here
67 }
68 *mem = 0; // expected-warning{{Use of memory after it is freed}}
69}
70
71
72class MultipleInheritance : public Subclass, public SmartPointer {
73public:
74 MultipleInheritance(void *a, void *b) : Subclass(a), SmartPointer(b) {}
75};
76
77void testMultipleInheritance1() {
78 char *mem = (char*)malloc(4);
79 {
80 MultipleInheritance Deleter(mem, 0);
81 // Remove dead bindings...
82 doSomething();
83 // destructor called here
84 }
85 *mem = 0; // expected-warning{{Use of memory after it is freed}}
86}
87
88void testMultipleInheritance2() {
89 char *mem = (char*)malloc(4);
90 {
91 MultipleInheritance Deleter(0, mem);
92 // Remove dead bindings...
93 doSomething();
94 // destructor called here
95 }
96 *mem = 0; // expected-warning{{Use of memory after it is freed}}
97}
98
99void testMultipleInheritance3() {
100 char *mem = (char*)malloc(4);
101 {
102 MultipleInheritance Deleter(mem, mem);
103 // Remove dead bindings...
104 doSomething();
105 // destructor called here
Jordan Rose2be6e302012-08-28 20:52:13 +0000106 // expected-warning@28 {{Attempt to free released memory}}
Jordan Rosea4c0d212012-07-26 20:04:05 +0000107 }
108}
Jordan Rose54529a32012-07-26 20:04:21 +0000109
110
111class SmartPointerMember {
112 SmartPointer P;
113public:
114 SmartPointerMember(void *x) : P(x) {}
115};
116
117void testSmartPointerMember() {
118 char *mem = (char*)malloc(4);
119 {
120 SmartPointerMember Deleter(mem);
121 // Remove dead bindings...
122 doSomething();
123 // destructor called here
124 }
125 *mem = 0; // expected-warning{{Use of memory after it is freed}}
126}
Jordan Rose20edae82012-07-26 20:04:25 +0000127
128
129struct IntWrapper {
130 IntWrapper() : x(0) {}
131 ~IntWrapper();
132 int *x;
133};
134
135void testArrayInvalidation() {
136 int i = 42;
137 int j = 42;
138
139 {
140 IntWrapper arr[2];
141
142 // There should be no undefined value warnings here.
143 // Eventually these should be TRUE as well, but right now
144 // we can't handle array constructors.
145 clang_analyzer_eval(arr[0].x == 0); // expected-warning{{UNKNOWN}}
146 clang_analyzer_eval(arr[1].x == 0); // expected-warning{{UNKNOWN}}
147
148 arr[0].x = &i;
149 arr[1].x = &j;
150 clang_analyzer_eval(*arr[0].x == 42); // expected-warning{{TRUE}}
151 clang_analyzer_eval(*arr[1].x == 42); // expected-warning{{TRUE}}
152 }
153
154 // The destructors should have invalidated i and j.
155 clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}}
156 clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}}
157}
Jordan Rose25bc20f2012-07-26 20:04:30 +0000158
159
160
161// Don't crash on a default argument inside an initializer.
162struct DefaultArg {
163 DefaultArg(int x = 0) {}
164 ~DefaultArg();
165};
166
167struct InheritsDefaultArg : DefaultArg {
168 InheritsDefaultArg() {}
169 virtual ~InheritsDefaultArg();
170};
171
172void testDefaultArg() {
173 InheritsDefaultArg a;
174 // Force a bug to be emitted.
175 *(char *)0 = 1; // expected-warning{{Dereference of null pointer}}
176}
Jordan Rose0f6d63b2012-08-15 00:51:56 +0000177
178
179namespace DestructorVirtualCalls {
180 class A {
181 public:
182 int *out1, *out2, *out3;
183
184 virtual int get() { return 1; }
185
186 ~A() {
187 *out1 = get();
188 }
189 };
190
191 class B : public A {
192 public:
193 virtual int get() { return 2; }
194
195 ~B() {
196 *out2 = get();
197 }
198 };
199
200 class C : public B {
201 public:
202 virtual int get() { return 3; }
203
204 ~C() {
205 *out3 = get();
206 }
207 };
208
209 void test() {
210 int a, b, c;
211
212 // New scope for the C object.
213 {
214 C obj;
215 clang_analyzer_eval(obj.get() == 3); // expected-warning{{TRUE}}
216
217 // Sanity check for devirtualization.
218 A *base = &obj;
219 clang_analyzer_eval(base->get() == 3); // expected-warning{{TRUE}}
220
221 obj.out1 = &a;
222 obj.out2 = &b;
223 obj.out3 = &c;
224 }
225
226 clang_analyzer_eval(a == 1); // expected-warning{{TRUE}}
227 clang_analyzer_eval(b == 2); // expected-warning{{TRUE}}
228 clang_analyzer_eval(c == 3); // expected-warning{{TRUE}}
229 }
230}
Jordan Rose2be6e302012-08-28 20:52:13 +0000231
232
233namespace DestructorsShouldNotAffectReturnValues {
234 class Dtor {
235 public:
236 ~Dtor() {
237 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
238 }
239 };
240
241 void *allocate() {
242 Dtor d;
243 return malloc(4); // no-warning
244 }
245
246 void test() {
247 // At one point we had an issue where the statements inside an
248 // inlined destructor kept us from finding the return statement,
249 // leading the analyzer to believe that the malloc'd memory had leaked.
250 void *p = allocate();
251 free(p); // no-warning
252 }
253}
Jordan Rose2bc96742012-09-06 20:37:08 +0000254
255namespace MultipleInheritanceVirtualDtors {
256 class VirtualDtor {
257 protected:
258 virtual ~VirtualDtor() {
259 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
260 }
261 };
262
263 class NonVirtualDtor {
264 protected:
265 ~NonVirtualDtor() {
266 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
267 }
268 };
269
270 class SubclassA : public VirtualDtor, public NonVirtualDtor {
271 public:
272 virtual ~SubclassA() {}
273 };
274 class SubclassB : public NonVirtualDtor, public VirtualDtor {
275 public:
276 virtual ~SubclassB() {}
277 };
278
279 void test() {
280 SubclassA a;
281 SubclassB b;
282 }
283}
Jordan Rose12f669e2012-09-11 00:31:02 +0000284
285namespace ExplicitDestructorCall {
286 class VirtualDtor {
287 public:
288 virtual ~VirtualDtor() {
289 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
290 }
291 };
292
293 class Subclass : public VirtualDtor {
294 public:
295 virtual ~Subclass() {
296 clang_analyzer_checkInlined(false); // no-warning
297 }
298 };
299
300 void destroy(Subclass *obj) {
301 obj->VirtualDtor::~VirtualDtor();
302 }
303}
Jordan Rose4cfdbff2012-12-12 19:13:44 +0000304
305
306namespace MultidimensionalArrays {
307 void testArrayInvalidation() {
308 int i = 42;
309 int j = 42;
310
311 {
312 IntWrapper arr[2][2];
313
314 // There should be no undefined value warnings here.
315 // Eventually these should be TRUE as well, but right now
316 // we can't handle array constructors.
317 clang_analyzer_eval(arr[0][0].x == 0); // expected-warning{{UNKNOWN}}
318 clang_analyzer_eval(arr[1][1].x == 0); // expected-warning{{UNKNOWN}}
319
320 arr[0][0].x = &i;
321 arr[1][1].x = &j;
322 clang_analyzer_eval(*arr[0][0].x == 42); // expected-warning{{TRUE}}
323 clang_analyzer_eval(*arr[1][1].x == 42); // expected-warning{{TRUE}}
324 }
325
326 // The destructors should have invalidated i and j.
327 clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}}
328 clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}}
329 }
330}
Jordan Rose8647ffc2013-04-03 21:16:58 +0000331
332namespace LifetimeExtension {
333 struct IntWrapper {
334 int x;
335 IntWrapper(int y) : x(y) {}
336 IntWrapper() {
337 extern void use(int);
338 use(x); // no-warning
339 }
340 };
341
342 struct DerivedWrapper : public IntWrapper {
343 DerivedWrapper(int y) : IntWrapper(y) {}
344 };
345
346 DerivedWrapper get() {
347 return DerivedWrapper(1);
348 }
349
350 void test() {
351 const DerivedWrapper &d = get(); // lifetime extended here
352 }
353
354
355 class SaveOnDestruct {
356 public:
357 static int lastOutput;
358 int value;
359
360 SaveOnDestruct();
361 ~SaveOnDestruct() {
362 lastOutput = value;
363 }
364 };
365
366 void testSimple() {
367 {
368 const SaveOnDestruct &obj = SaveOnDestruct();
369 if (obj.value != 42)
370 return;
371 // destructor called here
372 }
373
374 clang_analyzer_eval(SaveOnDestruct::lastOutput == 42); // expected-warning{{TRUE}}
375 }
376
Jordan Rose398fb002014-04-01 16:39:33 +0000377 struct NRCheck {
378 bool bool_;
379 NRCheck():bool_(true) {}
380 ~NRCheck() __attribute__((noreturn));
381 operator bool() const { return bool_; }
382 };
383
384 struct CheckAutoDestructor {
385 bool bool_;
386 CheckAutoDestructor():bool_(true) {}
387 operator bool() const { return bool_; }
388 };
389
390 struct CheckCustomDestructor {
391 bool bool_;
392 CheckCustomDestructor():bool_(true) {}
393 ~CheckCustomDestructor();
394 operator bool() const { return bool_; }
395 };
396
397 bool testUnnamedNR() {
398 if (NRCheck())
399 return true;
400 return false;
401 }
402
403 bool testNamedNR() {
404 if (NRCheck c = NRCheck())
405 return true;
406 return false;
407 }
408
409 bool testUnnamedAutoDestructor() {
410 if (CheckAutoDestructor())
411 return true;
412 return false;
413 }
414
415 bool testNamedAutoDestructor() {
416 if (CheckAutoDestructor c = CheckAutoDestructor())
417 return true;
418 return false;
419 }
420
421 bool testUnnamedCustomDestructor() {
422 if (CheckCustomDestructor())
423 return true;
424 return false;
425 }
426
427 // This case used to cause an unexpected "Undefined or garbage value returned
428 // to caller" warning
Jordan Rose9c8a5ff2014-04-07 16:36:08 +0000429 bool testNamedCustomDestructor() {
430 if (CheckCustomDestructor c = CheckCustomDestructor())
431 return true;
432 return false;
433 }
Jordan Rose8a5a0942014-04-05 02:01:41 +0000434
435 bool testMultipleTemporariesCustomDestructor() {
436 if (CheckCustomDestructor c = (CheckCustomDestructor(), CheckCustomDestructor()))
Jordan Rose398fb002014-04-01 16:39:33 +0000437 return true;
438 return false;
439 }
440
Jordan Rose8647ffc2013-04-03 21:16:58 +0000441 class VirtualDtorBase {
442 public:
443 int value;
444 virtual ~VirtualDtorBase() {}
445 };
446
447 class SaveOnVirtualDestruct : public VirtualDtorBase {
448 public:
449 static int lastOutput;
450
451 SaveOnVirtualDestruct();
452 virtual ~SaveOnVirtualDestruct() {
453 lastOutput = value;
454 }
455 };
456
457 void testVirtual() {
458 {
459 const VirtualDtorBase &obj = SaveOnVirtualDestruct();
460 if (obj.value != 42)
461 return;
462 // destructor called here
463 }
464
465 clang_analyzer_eval(SaveOnVirtualDestruct::lastOutput == 42); // expected-warning{{TRUE}}
466 }
467}
Pavel Labathf77e7362013-07-03 08:23:49 +0000468
469namespace NoReturn {
470 struct NR {
471 ~NR() __attribute__((noreturn));
472 };
473
474 void f(int **x) {
475 NR nr;
476 }
477
478 void g() {
479 int *x;
480 f(&x);
481 *x = 47; // no warning
482 }
Jordan Rose398fb002014-04-01 16:39:33 +0000483
484 void g2(int *x) {
485 if (! x) NR();
Jordan Rose8a5a0942014-04-05 02:01:41 +0000486 *x = 47; // no warning
Jordan Rose398fb002014-04-01 16:39:33 +0000487 }
Pavel Labathf77e7362013-07-03 08:23:49 +0000488}
Jordan Rose316cdda2013-07-23 02:15:20 +0000489
490namespace PseudoDtor {
491 template <typename T>
492 void destroy(T &obj) {
493 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
494 obj.~T();
495 }
496
497 void test() {
498 int i;
499 destroy(i);
500 clang_analyzer_eval(true); // expected-warning{{TRUE}}
501 }
502}
Matt Beaumont-Gay093f2402013-09-09 21:07:58 +0000503
504namespace Incomplete {
505 class Foo; // expected-note{{forward declaration}}
506 void f(Foo *foo) { delete foo; } // expected-warning{{deleting pointer to incomplete type}}
507}
Ismail Pazarbasid60db642015-09-22 19:33:15 +0000508
509namespace TypeTraitExpr {
510template <bool IsSimple, typename T>
511struct copier {
512 static void do_copy(T *dest, const T *src, unsigned count);
513};
514template <typename T, typename U>
515void do_copy(T *dest, const U *src, unsigned count) {
516 const bool IsSimple = __is_trivial(T) && __is_same(T, U);
517 copier<IsSimple, T>::do_copy(dest, src, count);
518}
519struct NonTrivial {
520 int *p;
521 NonTrivial() : p(new int[1]) { p[0] = 0; }
522 NonTrivial(const NonTrivial &other) {
523 p = new int[1];
524 do_copy(p, other.p, 1);
525 }
526 NonTrivial &operator=(const NonTrivial &other) {
527 p = other.p;
528 return *this;
529 }
530 ~NonTrivial() {
531 delete[] p; // expected-warning {{free released memory}}
532 }
533};
534
535void f() {
536 NonTrivial nt1;
537 NonTrivial nt2(nt1);
538 nt1 = nt2;
539 clang_analyzer_eval(__is_trivial(NonTrivial)); // expected-warning{{FALSE}}
540 clang_analyzer_eval(__alignof(NonTrivial) > 0); // expected-warning{{TRUE}}
541}
542}