dtor.cpp revision 0ad36baedc516005cb6ea97d96327517ebfe5138
1// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -analyzer-ipa=inlining -cfg-add-implicit-dtors -Wno-null-dereference -verify %s
2
3void clang_analyzer_eval(bool);
4
5class A {
6public:
7  ~A() {
8    int *x = 0;
9    *x = 3; // expected-warning{{Dereference of null pointer}}
10  }
11};
12
13int main() {
14  A a;
15}
16
17
18typedef __typeof(sizeof(int)) size_t;
19void *malloc(size_t);
20void free(void *);
21
22class SmartPointer {
23  void *X;
24public:
25  SmartPointer(void *x) : X(x) {}
26  ~SmartPointer() {
27    free(X);
28  }
29};
30
31void testSmartPointer() {
32  char *mem = (char*)malloc(4);
33  {
34    SmartPointer Deleter(mem);
35    // destructor called here
36  }
37  *mem = 0; // expected-warning{{Use of memory after it is freed}}
38}
39
40
41void doSomething();
42void testSmartPointer2() {
43  char *mem = (char*)malloc(4);
44  {
45    SmartPointer Deleter(mem);
46    // Remove dead bindings...
47    doSomething();
48    // destructor called here
49  }
50  *mem = 0; // expected-warning{{Use of memory after it is freed}}
51}
52
53
54class Subclass : public SmartPointer {
55public:
56  Subclass(void *x) : SmartPointer(x) {}
57};
58
59void testSubclassSmartPointer() {
60  char *mem = (char*)malloc(4);
61  {
62    Subclass Deleter(mem);
63    // Remove dead bindings...
64    doSomething();
65    // destructor called here
66  }
67  *mem = 0; // expected-warning{{Use of memory after it is freed}}
68}
69
70
71class MultipleInheritance : public Subclass, public SmartPointer {
72public:
73  MultipleInheritance(void *a, void *b) : Subclass(a), SmartPointer(b) {}
74};
75
76void testMultipleInheritance1() {
77  char *mem = (char*)malloc(4);
78  {
79    MultipleInheritance Deleter(mem, 0);
80    // Remove dead bindings...
81    doSomething();
82    // destructor called here
83  }
84  *mem = 0; // expected-warning{{Use of memory after it is freed}}
85}
86
87void testMultipleInheritance2() {
88  char *mem = (char*)malloc(4);
89  {
90    MultipleInheritance Deleter(0, mem);
91    // Remove dead bindings...
92    doSomething();
93    // destructor called here
94  }
95  *mem = 0; // expected-warning{{Use of memory after it is freed}}
96}
97
98void testMultipleInheritance3() {
99  char *mem = (char*)malloc(4);
100  {
101    MultipleInheritance Deleter(mem, mem);
102    // Remove dead bindings...
103    doSomething();
104    // destructor called here
105    // expected-warning@27 {{Attempt to free released memory}}
106  }
107}
108
109
110class SmartPointerMember {
111  SmartPointer P;
112public:
113  SmartPointerMember(void *x) : P(x) {}
114};
115
116void testSmartPointerMember() {
117  char *mem = (char*)malloc(4);
118  {
119    SmartPointerMember Deleter(mem);
120    // Remove dead bindings...
121    doSomething();
122    // destructor called here
123  }
124  *mem = 0; // expected-warning{{Use of memory after it is freed}}
125}
126
127
128struct IntWrapper {
129  IntWrapper() : x(0) {}
130  ~IntWrapper();
131  int *x;
132};
133
134void testArrayInvalidation() {
135  int i = 42;
136  int j = 42;
137
138  {
139    IntWrapper arr[2];
140
141    // There should be no undefined value warnings here.
142    // Eventually these should be TRUE as well, but right now
143    // we can't handle array constructors.
144    clang_analyzer_eval(arr[0].x == 0); // expected-warning{{UNKNOWN}}
145    clang_analyzer_eval(arr[1].x == 0); // expected-warning{{UNKNOWN}}
146
147    arr[0].x = &i;
148    arr[1].x = &j;
149    clang_analyzer_eval(*arr[0].x == 42); // expected-warning{{TRUE}}
150    clang_analyzer_eval(*arr[1].x == 42); // expected-warning{{TRUE}}
151  }
152
153  // The destructors should have invalidated i and j.
154  clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}}
155  clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}}
156}
157
158
159
160// Don't crash on a default argument inside an initializer.
161struct DefaultArg {
162  DefaultArg(int x = 0) {}
163  ~DefaultArg();
164};
165
166struct InheritsDefaultArg : DefaultArg {
167  InheritsDefaultArg() {}
168  virtual ~InheritsDefaultArg();
169};
170
171void testDefaultArg() {
172  InheritsDefaultArg a;
173  // Force a bug to be emitted.
174  *(char *)0 = 1; // expected-warning{{Dereference of null pointer}}
175}
176
177
178namespace DestructorVirtualCalls {
179  class A {
180  public:
181    int *out1, *out2, *out3;
182
183    virtual int get() { return 1; }
184
185    ~A() {
186      *out1 = get();
187    }
188  };
189
190  class B : public A {
191  public:
192    virtual int get() { return 2; }
193
194    ~B() {
195      *out2 = get();
196    }
197  };
198
199  class C : public B {
200  public:
201    virtual int get() { return 3; }
202
203    ~C() {
204      *out3 = get();
205    }
206  };
207
208  void test() {
209    int a, b, c;
210
211    // New scope for the C object.
212    {
213      C obj;
214      clang_analyzer_eval(obj.get() == 3); // expected-warning{{TRUE}}
215
216      // Sanity check for devirtualization.
217      A *base = &obj;
218      clang_analyzer_eval(base->get() == 3); // expected-warning{{TRUE}}
219
220      obj.out1 = &a;
221      obj.out2 = &b;
222      obj.out3 = &c;
223    }
224
225    clang_analyzer_eval(a == 1); // expected-warning{{TRUE}}
226    clang_analyzer_eval(b == 2); // expected-warning{{TRUE}}
227    clang_analyzer_eval(c == 3); // expected-warning{{TRUE}}
228  }
229}
230