[ELF] Avoid make in elf::writeARMCmseImportLib
[llvm-project.git] / clang / test / Analysis / dtor.cpp
blobbda7d19522bdd8e2ffe7f75f9d4de5d58a25692a
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
3 void clang_analyzer_eval(bool);
4 void clang_analyzer_checkInlined(bool);
6 class A {
7 public:
8 ~A() {
9 int *x = 0;
10 *x = 3; // expected-warning{{Dereference of null pointer}}
14 int main() {
15 A a;
19 typedef __typeof(sizeof(int)) size_t;
20 void *malloc(size_t);
21 void free(void *);
23 class SmartPointer {
24 void *X;
25 public:
26 SmartPointer(void *x) : X(x) {}
27 ~SmartPointer() {
28 free(X);
32 void testSmartPointer() {
33 char *mem = (char*)malloc(4);
35 SmartPointer Deleter(mem);
36 // destructor called here
38 *mem = 0; // expected-warning{{Use of memory after it is freed}}
42 void doSomething();
43 void testSmartPointer2() {
44 char *mem = (char*)malloc(4);
46 SmartPointer Deleter(mem);
47 // Remove dead bindings...
48 doSomething();
49 // destructor called here
51 *mem = 0; // expected-warning{{Use of memory after it is freed}}
55 class Subclass : public SmartPointer {
56 public:
57 Subclass(void *x) : SmartPointer(x) {}
60 void testSubclassSmartPointer() {
61 char *mem = (char*)malloc(4);
63 Subclass Deleter(mem);
64 // Remove dead bindings...
65 doSomething();
66 // destructor called here
68 *mem = 0; // expected-warning{{Use of memory after it is freed}}
72 class MultipleInheritance : public Subclass, public SmartPointer {
73 public:
74 MultipleInheritance(void *a, void *b) : Subclass(a), SmartPointer(b) {}
77 void testMultipleInheritance1() {
78 char *mem = (char*)malloc(4);
80 MultipleInheritance Deleter(mem, 0);
81 // Remove dead bindings...
82 doSomething();
83 // destructor called here
85 *mem = 0; // expected-warning{{Use of memory after it is freed}}
88 void testMultipleInheritance2() {
89 char *mem = (char*)malloc(4);
91 MultipleInheritance Deleter(0, mem);
92 // Remove dead bindings...
93 doSomething();
94 // destructor called here
96 *mem = 0; // expected-warning{{Use of memory after it is freed}}
99 void testMultipleInheritance3() {
100 char *mem = (char*)malloc(4);
102 MultipleInheritance Deleter(mem, mem);
103 // Remove dead bindings...
104 doSomething();
105 // destructor called here
106 // expected-warning@28 {{Attempt to free released memory}}
111 class SmartPointerMember {
112 SmartPointer P;
113 public:
114 SmartPointerMember(void *x) : P(x) {}
117 void testSmartPointerMember() {
118 char *mem = (char*)malloc(4);
120 SmartPointerMember Deleter(mem);
121 // Remove dead bindings...
122 doSomething();
123 // destructor called here
125 *mem = 0; // expected-warning{{Use of memory after it is freed}}
129 struct IntWrapper {
130 IntWrapper() : x(0) {}
131 ~IntWrapper();
132 int *x;
135 void testArrayInvalidation() {
136 int i = 42;
137 int j = 42;
140 IntWrapper arr[2];
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}}
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}}
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}}
159 // Don't crash on a default argument inside an initializer.
160 struct DefaultArg {
161 DefaultArg(int x = 0) {}
162 ~DefaultArg();
165 struct InheritsDefaultArg : DefaultArg {
166 InheritsDefaultArg() {}
167 virtual ~InheritsDefaultArg();
170 void testDefaultArg() {
171 InheritsDefaultArg a;
172 // Force a bug to be emitted.
173 *(char *)0 = 1; // expected-warning{{Dereference of null pointer}}
177 namespace DestructorVirtualCalls {
178 class A {
179 public:
180 int *out1, *out2, *out3;
182 virtual int get() { return 1; }
184 ~A() {
185 *out1 = get();
189 class B : public A {
190 public:
191 virtual int get() { return 2; }
193 ~B() {
194 *out2 = get();
198 class C : public B {
199 public:
200 virtual int get() { return 3; }
202 ~C() {
203 *out3 = get();
207 void test() {
208 int a, b, c;
210 // New scope for the C object.
212 C obj;
213 clang_analyzer_eval(obj.get() == 3); // expected-warning{{TRUE}}
215 // Correctness check for devirtualization.
216 A *base = &obj;
217 clang_analyzer_eval(base->get() == 3); // expected-warning{{TRUE}}
219 obj.out1 = &a;
220 obj.out2 = &b;
221 obj.out3 = &c;
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}}
231 namespace DestructorsShouldNotAffectReturnValues {
232 class Dtor {
233 public:
234 ~Dtor() {
235 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
239 void *allocate() {
240 Dtor d;
241 return malloc(4); // no-warning
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
253 namespace MultipleInheritanceVirtualDtors {
254 class VirtualDtor {
255 protected:
256 virtual ~VirtualDtor() {
257 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
261 class NonVirtualDtor {
262 protected:
263 ~NonVirtualDtor() {
264 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
268 class SubclassA : public VirtualDtor, public NonVirtualDtor {
269 public:
270 virtual ~SubclassA() {}
272 class SubclassB : public NonVirtualDtor, public VirtualDtor {
273 public:
274 virtual ~SubclassB() {}
277 void test() {
278 SubclassA a;
279 SubclassB b;
283 namespace ExplicitDestructorCall {
284 class VirtualDtor {
285 public:
286 virtual ~VirtualDtor() {
287 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
291 class Subclass : public VirtualDtor {
292 public:
293 virtual ~Subclass() {
294 clang_analyzer_checkInlined(false); // no-warning
298 void destroy(Subclass *obj) {
299 obj->VirtualDtor::~VirtualDtor();
304 namespace MultidimensionalArrays {
305 void testArrayInvalidation() {
306 int i = 42;
307 int j = 42;
310 IntWrapper arr[2][2];
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}}
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}}
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}}
328 namespace LifetimeExtension {
329 struct IntWrapper {
330 int x;
331 IntWrapper(int y) : x(y) {}
332 IntWrapper() {
333 extern void use(int);
334 use(x); // no-warning
338 struct DerivedWrapper : public IntWrapper {
339 DerivedWrapper(int y) : IntWrapper(y) {}
342 DerivedWrapper get() {
343 return DerivedWrapper(1);
346 void test() {
347 const DerivedWrapper &d = get(); // lifetime extended here
351 class SaveOnDestruct {
352 public:
353 static int lastOutput;
354 int value;
356 SaveOnDestruct();
357 ~SaveOnDestruct() {
358 lastOutput = value;
362 void testSimple() {
364 const SaveOnDestruct &obj = SaveOnDestruct();
365 if (obj.value != 42)
366 return;
367 // destructor called here
370 clang_analyzer_eval(SaveOnDestruct::lastOutput == 42); // expected-warning{{TRUE}}
373 struct NRCheck {
374 bool bool_;
375 NRCheck():bool_(true) {}
376 ~NRCheck() __attribute__((noreturn));
377 operator bool() const { return bool_; }
380 struct CheckAutoDestructor {
381 bool bool_;
382 CheckAutoDestructor():bool_(true) {}
383 operator bool() const { return bool_; }
386 struct CheckCustomDestructor {
387 bool bool_;
388 CheckCustomDestructor():bool_(true) {}
389 ~CheckCustomDestructor();
390 operator bool() const { return bool_; }
393 bool testUnnamedNR() {
394 if (NRCheck())
395 return true;
396 return false;
399 bool testNamedNR() {
400 if (NRCheck c = NRCheck())
401 return true;
402 return false;
405 bool testUnnamedAutoDestructor() {
406 if (CheckAutoDestructor())
407 return true;
408 return false;
411 bool testNamedAutoDestructor() {
412 if (CheckAutoDestructor c = CheckAutoDestructor())
413 return true;
414 return false;
417 bool testUnnamedCustomDestructor() {
418 if (CheckCustomDestructor())
419 return true;
420 return false;
423 // This case used to cause an unexpected "Undefined or garbage value returned
424 // to caller" warning
425 bool testNamedCustomDestructor() {
426 if (CheckCustomDestructor c = CheckCustomDestructor())
427 return true;
428 return false;
431 bool testMultipleTemporariesCustomDestructor() {
432 if (CheckCustomDestructor c = (CheckCustomDestructor(), CheckCustomDestructor()))
433 return true;
434 return false;
437 class VirtualDtorBase {
438 public:
439 int value;
440 virtual ~VirtualDtorBase() {}
443 class SaveOnVirtualDestruct : public VirtualDtorBase {
444 public:
445 static int lastOutput;
447 SaveOnVirtualDestruct();
448 virtual ~SaveOnVirtualDestruct() {
449 lastOutput = value;
453 void testVirtual() {
455 const VirtualDtorBase &obj = SaveOnVirtualDestruct();
456 if (obj.value != 42)
457 return;
458 // destructor called here
461 clang_analyzer_eval(SaveOnVirtualDestruct::lastOutput == 42); // expected-warning{{TRUE}}
465 namespace NoReturn {
466 struct NR {
467 ~NR() __attribute__((noreturn));
470 void f(int **x) {
471 NR nr;
474 void g() {
475 int *x;
476 f(&x);
477 *x = 47; // no warning
480 void g2(int *x) {
481 if (! x) NR();
482 *x = 47; // no warning
486 namespace PseudoDtor {
487 template <typename T>
488 void destroy(T &obj) {
489 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
490 obj.~T();
493 void test() {
494 int i;
495 destroy(i);
496 clang_analyzer_eval(true); // expected-warning{{TRUE}}
500 namespace Incomplete {
501 class Foo; // expected-note{{forward declaration}}
502 void f(Foo *foo) { delete foo; } // expected-warning{{deleting pointer to incomplete type}}
505 namespace TypeTraitExpr {
506 template <bool IsSimple, typename T>
507 struct copier {
508 static void do_copy(T *dest, const T *src, unsigned count);
510 template <typename T, typename U>
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);
515 struct NonTrivial {
516 int *p;
517 NonTrivial() : p(new int[1]) { p[0] = 0; }
518 NonTrivial(const NonTrivial &other) {
519 p = new int[1];
520 do_copy(p, other.p, 1);
522 NonTrivial &operator=(const NonTrivial &other) {
523 p = other.p;
524 return *this;
526 ~NonTrivial() {
527 delete[] p; // expected-warning {{free released memory}}
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}}
540 namespace dtor_over_loc_concrete_int {
541 struct A {
542 ~A() {}
545 struct B {
546 A a;
547 ~B() {}
550 struct C : A {
551 ~C() {}
554 void testB() {
555 B *b = (B *)-1;
556 b->~B(); // no-crash
559 void testC() {
560 C *c = (C *)-1;
561 c->~C(); // no-crash
564 void testAutoDtor() {
565 const A &a = *(A *)-1;
566 // no-crash
568 } // namespace dtor_over_loc_concrete_int
570 // Test overriden new/delete operators
571 struct CustomOperators {
572 void *operator new(size_t count) {
573 return malloc(count);
576 void operator delete(void *addr) {
577 free(addr);
580 private:
581 int i;
584 void compliant() {
585 auto *a = new CustomOperators();
586 delete a;
589 void overrideLeak() {
590 auto *a = new CustomOperators();
591 } // expected-warning{{Potential leak of memory pointed to by 'a'}}
593 void overrideDoubleDelete() {
594 auto *a = new CustomOperators();
595 delete a;
596 delete a; // expected-warning@577 {{Attempt to free released memory}}