1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -Wno-null-dereference -verify %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 // 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 }
158
159
160
161 // Don't crash on a default argument inside an initializer.
162 struct DefaultArg {
DefaultArgDefaultArg163 DefaultArg(int x = 0) {}
164 ~DefaultArg();
165 };
166
167 struct InheritsDefaultArg : DefaultArg {
InheritsDefaultArgInheritsDefaultArg168 InheritsDefaultArg() {}
169 virtual ~InheritsDefaultArg();
170 };
171
testDefaultArg()172 void testDefaultArg() {
173 InheritsDefaultArg a;
174 // Force a bug to be emitted.
175 *(char *)0 = 1; // expected-warning{{Dereference of null pointer}}
176 }
177
178
179 namespace DestructorVirtualCalls {
180 class A {
181 public:
182 int *out1, *out2, *out3;
183
get()184 virtual int get() { return 1; }
185
~A()186 ~A() {
187 *out1 = get();
188 }
189 };
190
191 class B : public A {
192 public:
get()193 virtual int get() { return 2; }
194
~B()195 ~B() {
196 *out2 = get();
197 }
198 };
199
200 class C : public B {
201 public:
get()202 virtual int get() { return 3; }
203
~C()204 ~C() {
205 *out3 = get();
206 }
207 };
208
test()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 }
231
232
233 namespace DestructorsShouldNotAffectReturnValues {
234 class Dtor {
235 public:
~Dtor()236 ~Dtor() {
237 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
238 }
239 };
240
allocate()241 void *allocate() {
242 Dtor d;
243 return malloc(4); // no-warning
244 }
245
test()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 }
254
255 namespace MultipleInheritanceVirtualDtors {
256 class VirtualDtor {
257 protected:
~VirtualDtor()258 virtual ~VirtualDtor() {
259 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
260 }
261 };
262
263 class NonVirtualDtor {
264 protected:
~NonVirtualDtor()265 ~NonVirtualDtor() {
266 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
267 }
268 };
269
270 class SubclassA : public VirtualDtor, public NonVirtualDtor {
271 public:
~SubclassA()272 virtual ~SubclassA() {}
273 };
274 class SubclassB : public NonVirtualDtor, public VirtualDtor {
275 public:
~SubclassB()276 virtual ~SubclassB() {}
277 };
278
test()279 void test() {
280 SubclassA a;
281 SubclassB b;
282 }
283 }
284
285 namespace ExplicitDestructorCall {
286 class VirtualDtor {
287 public:
~VirtualDtor()288 virtual ~VirtualDtor() {
289 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
290 }
291 };
292
293 class Subclass : public VirtualDtor {
294 public:
~Subclass()295 virtual ~Subclass() {
296 clang_analyzer_checkInlined(false); // no-warning
297 }
298 };
299
destroy(Subclass * obj)300 void destroy(Subclass *obj) {
301 obj->VirtualDtor::~VirtualDtor();
302 }
303 }
304
305
306 namespace MultidimensionalArrays {
testArrayInvalidation()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 }
331