1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection,cplusplus -analyzer-config c++-inlining=destructors -Wno-null-dereference -Wno-inaccessible-base -verify -analyzer-config eagerly-assume=false %s
2
3 void clang_analyzer_eval(bool);
4 void clang_analyzer_checkInlined(bool);
5
6 class A {
7 public:
~A()8 ~A() {
9 int *x = 0;
10 *x = 3; // expected-warning{{Dereference of null pointer}}
11 }
12 };
13
main()14 int main() {
15 A a;
16 }
17
18
19 typedef __typeof(sizeof(int)) size_t;
20 void *malloc(size_t);
21 void free(void *);
22
23 class SmartPointer {
24 void *X;
25 public:
SmartPointer(void * x)26 SmartPointer(void *x) : X(x) {}
~SmartPointer()27 ~SmartPointer() {
28 free(X);
29 }
30 };
31
testSmartPointer()32 void 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 }
40
41
42 void doSomething();
testSmartPointer2()43 void 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
55 class Subclass : public SmartPointer {
56 public:
Subclass(void * x)57 Subclass(void *x) : SmartPointer(x) {}
58 };
59
testSubclassSmartPointer()60 void 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
72 class MultipleInheritance : public Subclass, public SmartPointer {
73 public:
MultipleInheritance(void * a,void * b)74 MultipleInheritance(void *a, void *b) : Subclass(a), SmartPointer(b) {}
75 };
76
testMultipleInheritance1()77 void 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
testMultipleInheritance2()88 void 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
testMultipleInheritance3()99 void testMultipleInheritance3() {
100 char *mem = (char*)malloc(4);
101 {
102 MultipleInheritance Deleter(mem, mem);
103 // Remove dead bindings...
104 doSomething();
105 // destructor called here
106 // expected-warning@28 {{Attempt to free released memory}}
107 }
108 }
109
110
111 class SmartPointerMember {
112 SmartPointer P;
113 public:
SmartPointerMember(void * x)114 SmartPointerMember(void *x) : P(x) {}
115 };
116
testSmartPointerMember()117 void 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 }
127
128
129 struct IntWrapper {
IntWrapperIntWrapper130 IntWrapper() : x(0) {}
131 ~IntWrapper();
132 int *x;
133 };
134
testArrayInvalidation()135 void 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 clang_analyzer_eval(arr[0].x == 0); // expected-warning{{TRUE}}
144 clang_analyzer_eval(arr[1].x == 0); // expected-warning{{TRUE}}
145
146 arr[0].x = &i;
147 arr[1].x = &j;
148 clang_analyzer_eval(*arr[0].x == 42); // expected-warning{{TRUE}}
149 clang_analyzer_eval(*arr[1].x == 42); // expected-warning{{TRUE}}
150 }
151
152 // The destructors should have invalidated i and j.
153 clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}}
154 clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}}
155 }
156
157
158
159 // Don't crash on a default argument inside an initializer.
160 struct DefaultArg {
DefaultArgDefaultArg161 DefaultArg(int x = 0) {}
162 ~DefaultArg();
163 };
164
165 struct InheritsDefaultArg : DefaultArg {
InheritsDefaultArgInheritsDefaultArg166 InheritsDefaultArg() {}
167 virtual ~InheritsDefaultArg();
168 };
169
testDefaultArg()170 void testDefaultArg() {
171 InheritsDefaultArg a;
172 // Force a bug to be emitted.
173 *(char *)0 = 1; // expected-warning{{Dereference of null pointer}}
174 }
175
176
177 namespace DestructorVirtualCalls {
178 class A {
179 public:
180 int *out1, *out2, *out3;
181
get()182 virtual int get() { return 1; }
183
~A()184 ~A() {
185 *out1 = get();
186 }
187 };
188
189 class B : public A {
190 public:
get()191 virtual int get() { return 2; }
192
~B()193 ~B() {
194 *out2 = get();
195 }
196 };
197
198 class C : public B {
199 public:
get()200 virtual int get() { return 3; }
201
~C()202 ~C() {
203 *out3 = get();
204 }
205 };
206
test()207 void test() {
208 int a, b, c;
209
210 // New scope for the C object.
211 {
212 C obj;
213 clang_analyzer_eval(obj.get() == 3); // expected-warning{{TRUE}}
214
215 // Correctness check for devirtualization.
216 A *base = &obj;
217 clang_analyzer_eval(base->get() == 3); // expected-warning{{TRUE}}
218
219 obj.out1 = &a;
220 obj.out2 = &b;
221 obj.out3 = &c;
222 }
223
224 clang_analyzer_eval(a == 1); // expected-warning{{TRUE}}
225 clang_analyzer_eval(b == 2); // expected-warning{{TRUE}}
226 clang_analyzer_eval(c == 3); // expected-warning{{TRUE}}
227 }
228 }
229
230
231 namespace DestructorsShouldNotAffectReturnValues {
232 class Dtor {
233 public:
~Dtor()234 ~Dtor() {
235 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
236 }
237 };
238
allocate()239 void *allocate() {
240 Dtor d;
241 return malloc(4); // no-warning
242 }
243
test()244 void test() {
245 // At one point we had an issue where the statements inside an
246 // inlined destructor kept us from finding the return statement,
247 // leading the analyzer to believe that the malloc'd memory had leaked.
248 void *p = allocate();
249 free(p); // no-warning
250 }
251 }
252
253 namespace MultipleInheritanceVirtualDtors {
254 class VirtualDtor {
255 protected:
~VirtualDtor()256 virtual ~VirtualDtor() {
257 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
258 }
259 };
260
261 class NonVirtualDtor {
262 protected:
~NonVirtualDtor()263 ~NonVirtualDtor() {
264 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
265 }
266 };
267
268 class SubclassA : public VirtualDtor, public NonVirtualDtor {
269 public:
~SubclassA()270 virtual ~SubclassA() {}
271 };
272 class SubclassB : public NonVirtualDtor, public VirtualDtor {
273 public:
~SubclassB()274 virtual ~SubclassB() {}
275 };
276
test()277 void test() {
278 SubclassA a;
279 SubclassB b;
280 }
281 }
282
283 namespace ExplicitDestructorCall {
284 class VirtualDtor {
285 public:
~VirtualDtor()286 virtual ~VirtualDtor() {
287 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
288 }
289 };
290
291 class Subclass : public VirtualDtor {
292 public:
~Subclass()293 virtual ~Subclass() {
294 clang_analyzer_checkInlined(false); // no-warning
295 }
296 };
297
destroy(Subclass * obj)298 void destroy(Subclass *obj) {
299 obj->VirtualDtor::~VirtualDtor();
300 }
301 }
302
303
304 namespace MultidimensionalArrays {
testArrayInvalidation()305 void testArrayInvalidation() {
306 int i = 42;
307 int j = 42;
308
309 {
310 IntWrapper arr[2][2];
311
312 // There should be no undefined value warnings here.
313 clang_analyzer_eval(arr[0][0].x == 0); // expected-warning{{TRUE}}
314 clang_analyzer_eval(arr[1][1].x == 0); // expected-warning{{TRUE}}
315
316 arr[0][0].x = &i;
317 arr[1][1].x = &j;
318 clang_analyzer_eval(*arr[0][0].x == 42); // expected-warning{{TRUE}}
319 clang_analyzer_eval(*arr[1][1].x == 42); // expected-warning{{TRUE}}
320 }
321
322 // The destructors should have invalidated i and j.
323 clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}}
324 clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}}
325 }
326 }
327
328 namespace LifetimeExtension {
329 struct IntWrapper {
330 int x;
IntWrapperLifetimeExtension::IntWrapper331 IntWrapper(int y) : x(y) {}
IntWrapperLifetimeExtension::IntWrapper332 IntWrapper() {
333 extern void use(int);
334 use(x); // no-warning
335 }
336 };
337
338 struct DerivedWrapper : public IntWrapper {
DerivedWrapperLifetimeExtension::DerivedWrapper339 DerivedWrapper(int y) : IntWrapper(y) {}
340 };
341
get()342 DerivedWrapper get() {
343 return DerivedWrapper(1);
344 }
345
test()346 void test() {
347 const DerivedWrapper &d = get(); // lifetime extended here
348 }
349
350
351 class SaveOnDestruct {
352 public:
353 static int lastOutput;
354 int value;
355
356 SaveOnDestruct();
~SaveOnDestruct()357 ~SaveOnDestruct() {
358 lastOutput = value;
359 }
360 };
361
testSimple()362 void testSimple() {
363 {
364 const SaveOnDestruct &obj = SaveOnDestruct();
365 if (obj.value != 42)
366 return;
367 // destructor called here
368 }
369
370 clang_analyzer_eval(SaveOnDestruct::lastOutput == 42); // expected-warning{{TRUE}}
371 }
372
373 struct NRCheck {
374 bool bool_;
NRCheckLifetimeExtension::NRCheck375 NRCheck():bool_(true) {}
376 ~NRCheck() __attribute__((noreturn));
operator boolLifetimeExtension::NRCheck377 operator bool() const { return bool_; }
378 };
379
380 struct CheckAutoDestructor {
381 bool bool_;
CheckAutoDestructorLifetimeExtension::CheckAutoDestructor382 CheckAutoDestructor():bool_(true) {}
operator boolLifetimeExtension::CheckAutoDestructor383 operator bool() const { return bool_; }
384 };
385
386 struct CheckCustomDestructor {
387 bool bool_;
CheckCustomDestructorLifetimeExtension::CheckCustomDestructor388 CheckCustomDestructor():bool_(true) {}
389 ~CheckCustomDestructor();
operator boolLifetimeExtension::CheckCustomDestructor390 operator bool() const { return bool_; }
391 };
392
testUnnamedNR()393 bool testUnnamedNR() {
394 if (NRCheck())
395 return true;
396 return false;
397 }
398
testNamedNR()399 bool testNamedNR() {
400 if (NRCheck c = NRCheck())
401 return true;
402 return false;
403 }
404
testUnnamedAutoDestructor()405 bool testUnnamedAutoDestructor() {
406 if (CheckAutoDestructor())
407 return true;
408 return false;
409 }
410
testNamedAutoDestructor()411 bool testNamedAutoDestructor() {
412 if (CheckAutoDestructor c = CheckAutoDestructor())
413 return true;
414 return false;
415 }
416
testUnnamedCustomDestructor()417 bool testUnnamedCustomDestructor() {
418 if (CheckCustomDestructor())
419 return true;
420 return false;
421 }
422
423 // This case used to cause an unexpected "Undefined or garbage value returned
424 // to caller" warning
testNamedCustomDestructor()425 bool testNamedCustomDestructor() {
426 if (CheckCustomDestructor c = CheckCustomDestructor())
427 return true;
428 return false;
429 }
430
testMultipleTemporariesCustomDestructor()431 bool testMultipleTemporariesCustomDestructor() {
432 if (CheckCustomDestructor c = (CheckCustomDestructor(), CheckCustomDestructor()))
433 return true;
434 return false;
435 }
436
437 class VirtualDtorBase {
438 public:
439 int value;
~VirtualDtorBase()440 virtual ~VirtualDtorBase() {}
441 };
442
443 class SaveOnVirtualDestruct : public VirtualDtorBase {
444 public:
445 static int lastOutput;
446
447 SaveOnVirtualDestruct();
~SaveOnVirtualDestruct()448 virtual ~SaveOnVirtualDestruct() {
449 lastOutput = value;
450 }
451 };
452
testVirtual()453 void testVirtual() {
454 {
455 const VirtualDtorBase &obj = SaveOnVirtualDestruct();
456 if (obj.value != 42)
457 return;
458 // destructor called here
459 }
460
461 clang_analyzer_eval(SaveOnVirtualDestruct::lastOutput == 42); // expected-warning{{TRUE}}
462 }
463 }
464
465 namespace NoReturn {
466 struct NR {
467 ~NR() __attribute__((noreturn));
468 };
469
f(int ** x)470 void f(int **x) {
471 NR nr;
472 }
473
g()474 void g() {
475 int *x;
476 f(&x);
477 *x = 47; // no warning
478 }
479
g2(int * x)480 void g2(int *x) {
481 if (! x) NR();
482 *x = 47; // no warning
483 }
484 }
485
486 namespace PseudoDtor {
487 template <typename T>
destroy(T & obj)488 void destroy(T &obj) {
489 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
490 obj.~T();
491 }
492
test()493 void test() {
494 int i;
495 destroy(i);
496 clang_analyzer_eval(true); // expected-warning{{TRUE}}
497 }
498 }
499
500 namespace Incomplete {
501 class Foo; // expected-note{{forward declaration}}
f(Foo * foo)502 void f(Foo *foo) { delete foo; } // expected-warning{{deleting pointer to incomplete type}}
503 }
504
505 namespace TypeTraitExpr {
506 template <bool IsSimple, typename T>
507 struct copier {
508 static void do_copy(T *dest, const T *src, unsigned count);
509 };
510 template <typename T, typename U>
do_copy(T * dest,const U * src,unsigned count)511 void do_copy(T *dest, const U *src, unsigned count) {
512 const bool IsSimple = __is_trivial(T) && __is_same(T, U);
513 copier<IsSimple, T>::do_copy(dest, src, count);
514 }
515 struct NonTrivial {
516 int *p;
NonTrivialTypeTraitExpr::NonTrivial517 NonTrivial() : p(new int[1]) { p[0] = 0; }
NonTrivialTypeTraitExpr::NonTrivial518 NonTrivial(const NonTrivial &other) {
519 p = new int[1];
520 do_copy(p, other.p, 1);
521 }
operator =TypeTraitExpr::NonTrivial522 NonTrivial &operator=(const NonTrivial &other) {
523 p = other.p;
524 return *this;
525 }
~NonTrivialTypeTraitExpr::NonTrivial526 ~NonTrivial() {
527 delete[] p; // expected-warning {{free released memory}}
528 }
529 };
530
f()531 void f() {
532 NonTrivial nt1;
533 NonTrivial nt2(nt1);
534 nt1 = nt2;
535 clang_analyzer_eval(__is_trivial(NonTrivial)); // expected-warning{{FALSE}}
536 clang_analyzer_eval(__alignof(NonTrivial) > 0); // expected-warning{{TRUE}}
537 }
538 }
539
540 namespace dtor_over_loc_concrete_int {
541 struct A {
~Adtor_over_loc_concrete_int::A542 ~A() {}
543 };
544
545 struct B {
546 A a;
~Bdtor_over_loc_concrete_int::B547 ~B() {}
548 };
549
550 struct C : A {
~Cdtor_over_loc_concrete_int::C551 ~C() {}
552 };
553
testB()554 void testB() {
555 B *b = (B *)-1;
556 b->~B(); // no-crash
557 }
558
testC()559 void testC() {
560 C *c = (C *)-1;
561 c->~C(); // no-crash
562 }
563
testAutoDtor()564 void testAutoDtor() {
565 const A &a = *(A *)-1;
566 // no-crash
567 }
568 } // namespace dtor_over_loc_concrete_int
569
570 // Test overriden new/delete operators
571 struct CustomOperators {
operator newCustomOperators572 void *operator new(size_t count) {
573 return malloc(count);
574 }
575
operator deleteCustomOperators576 void operator delete(void *addr) {
577 free(addr);
578 }
579
580 private:
581 int i;
582 };
583
compliant()584 void compliant() {
585 auto *a = new CustomOperators();
586 delete a;
587 }
588
overrideLeak()589 void overrideLeak() {
590 auto *a = new CustomOperators();
591 } // expected-warning{{Potential leak of memory pointed to by 'a'}}
592
overrideDoubleDelete()593 void overrideDoubleDelete() {
594 auto *a = new CustomOperators();
595 delete a;
596 delete a; // expected-warning@577 {{Attempt to free released memory}}
597 }
598