1 | // RUN: %clang_analyze_cc1 -std=c++11 -fblocks -verify %s \ |
2 | // RUN: -analyzer-checker=core \ |
3 | // RUN: -analyzer-checker=cplusplus.NewDelete |
4 | // |
5 | // RUN: %clang_analyze_cc1 -DLEAKS -std=c++11 -fblocks -verify %s \ |
6 | // RUN: -analyzer-checker=core \ |
7 | // RUN: -analyzer-checker=cplusplus.NewDeleteLeaks |
8 | // |
9 | // RUN: %clang_analyze_cc1 -std=c++11 -fblocks -verify %s \ |
10 | // RUN: -analyzer-checker=core \ |
11 | // RUN: -analyzer-checker=cplusplus.NewDelete \ |
12 | // RUN: -analyzer-config c++-allocator-inlining=true |
13 | // |
14 | // RUN: %clang_analyze_cc1 -DLEAKS -std=c++11 -fblocks -verify %s \ |
15 | // RUN: -analyzer-checker=core \ |
16 | // RUN: -analyzer-checker=cplusplus.NewDeleteLeaks \ |
17 | // RUN: -analyzer-config c++-allocator-inlining=true |
18 | // |
19 | // RUN: %clang_analyze_cc1 -DTEST_INLINABLE_ALLOCATORS \ |
20 | // RUN: -std=c++11 -fblocks -verify %s \ |
21 | // RUN: -analyzer-checker=core \ |
22 | // RUN: -analyzer-checker=cplusplus.NewDelete |
23 | // |
24 | // RUN: %clang_analyze_cc1 -DLEAKS -DTEST_INLINABLE_ALLOCATORS \ |
25 | // RUN: -std=c++11 -fblocks -verify %s \ |
26 | // RUN: -analyzer-checker=core \ |
27 | // RUN: -analyzer-checker=cplusplus.NewDeleteLeaks |
28 | // |
29 | // RUN: %clang_analyze_cc1 -DTEST_INLINABLE_ALLOCATORS \ |
30 | // RUN: -std=c++11 -fblocks -verify %s \ |
31 | // RUN: -analyzer-checker=core \ |
32 | // RUN: -analyzer-checker=cplusplus.NewDelete \ |
33 | // RUN: -analyzer-config c++-allocator-inlining=true |
34 | // |
35 | // RUN: %clang_analyze_cc1 -DLEAKS -DTEST_INLINABLE_ALLOCATORS \ |
36 | // RUN: -std=c++11 -fblocks -verify %s \ |
37 | // RUN: -analyzer-checker=core \ |
38 | // RUN: -analyzer-checker=cplusplus.NewDeleteLeaks \ |
39 | // RUN: -analyzer-config c++-allocator-inlining=true |
40 | |
41 | #include "Inputs/system-header-simulator-cxx.h" |
42 | |
43 | typedef __typeof__(sizeof(int)) size_t; |
44 | extern "C" void *malloc(size_t); |
45 | extern "C" void free (void* ptr); |
46 | int *global; |
47 | |
48 | //------------------ |
49 | // check for leaks |
50 | //------------------ |
51 | |
52 | //----- Standard non-placement operators |
53 | void testGlobalOpNew() { |
54 | void *p = operator new(0); |
55 | } |
56 | #ifdef LEAKS |
57 | // expected-warning@-2{{Potential leak of memory pointed to by 'p'}} |
58 | #endif |
59 | |
60 | void testGlobalOpNewArray() { |
61 | void *p = operator new[](0); |
62 | } |
63 | #ifdef LEAKS |
64 | // expected-warning@-2{{Potential leak of memory pointed to by 'p'}} |
65 | #endif |
66 | |
67 | void testGlobalNewExpr() { |
68 | int *p = new int; |
69 | } |
70 | #ifdef LEAKS |
71 | // expected-warning@-2{{Potential leak of memory pointed to by 'p'}} |
72 | #endif |
73 | |
74 | void testGlobalNewExprArray() { |
75 | int *p = new int[0]; |
76 | } |
77 | #ifdef LEAKS |
78 | // expected-warning@-2{{Potential leak of memory pointed to by 'p'}} |
79 | #endif |
80 | |
81 | //----- Standard nothrow placement operators |
82 | void testGlobalNoThrowPlacementOpNewBeforeOverload() { |
83 | void *p = operator new(0, std::nothrow); |
84 | } |
85 | #ifdef LEAKS |
86 | #ifndef TEST_INLINABLE_ALLOCATORS |
87 | // expected-warning@-3{{Potential leak of memory pointed to by 'p'}} |
88 | #endif |
89 | #endif |
90 | |
91 | void testGlobalNoThrowPlacementExprNewBeforeOverload() { |
92 | int *p = new(std::nothrow) int; |
93 | } |
94 | #ifdef LEAKS |
95 | #ifndef TEST_INLINABLE_ALLOCATORS |
96 | // expected-warning@-3{{Potential leak of memory pointed to by 'p'}} |
97 | #endif |
98 | #endif |
99 | |
100 | //----- Standard pointer placement operators |
101 | void testGlobalPointerPlacementNew() { |
102 | int i; |
103 | |
104 | void *p1 = operator new(0, &i); // no warn |
105 | |
106 | void *p2 = operator new[](0, &i); // no warn |
107 | |
108 | int *p3 = new(&i) int; // no warn |
109 | |
110 | int *p4 = new(&i) int[0]; // no warn |
111 | } |
112 | |
113 | //----- Other cases |
114 | void testNewMemoryIsInHeap() { |
115 | int *p = new int; |
116 | if (global != p) // condition is always true as 'p' wraps a heap region that |
117 | // is different from a region wrapped by 'global' |
118 | global = p; // pointer escapes |
119 | } |
120 | |
121 | struct PtrWrapper { |
122 | int *x; |
123 | |
124 | PtrWrapper(int *input) : x(input) {} |
125 | }; |
126 | |
127 | void testNewInvalidationPlacement(PtrWrapper *w) { |
128 | // Ensure that we don't consider this a leak. |
129 | new (w) PtrWrapper(new int); // no warn |
130 | } |
131 | |
132 | //----------------------------------------- |
133 | // check for usage of zero-allocated memory |
134 | //----------------------------------------- |
135 | |
136 | void testUseZeroAlloc1() { |
137 | int *p = (int *)operator new(0); |
138 | *p = 1; // expected-warning {{Use of zero-allocated memory}} |
139 | delete p; |
140 | } |
141 | |
142 | int testUseZeroAlloc2() { |
143 | int *p = (int *)operator new[](0); |
144 | return p[0]; // expected-warning {{Use of zero-allocated memory}} |
145 | delete[] p; |
146 | } |
147 | |
148 | void f(int); |
149 | |
150 | void testUseZeroAlloc3() { |
151 | int *p = new int[0]; |
152 | f(*p); // expected-warning {{Use of zero-allocated memory}} |
153 | delete[] p; |
154 | } |
155 | |
156 | //--------------- |
157 | // other checks |
158 | //--------------- |
159 | |
160 | class SomeClass { |
161 | public: |
162 | void f(int *p); |
163 | }; |
164 | |
165 | void f(int *p1, int *p2 = 0, int *p3 = 0); |
166 | void g(SomeClass &c, ...); |
167 | |
168 | void testUseFirstArgAfterDelete() { |
169 | int *p = new int; |
170 | delete p; |
171 | f(p); // expected-warning{{Use of memory after it is freed}} |
172 | } |
173 | |
174 | void testUseMiddleArgAfterDelete(int *p) { |
175 | delete p; |
176 | f(0, p); // expected-warning{{Use of memory after it is freed}} |
177 | } |
178 | |
179 | void testUseLastArgAfterDelete(int *p) { |
180 | delete p; |
181 | f(0, 0, p); // expected-warning{{Use of memory after it is freed}} |
182 | } |
183 | |
184 | void testUseSeveralArgsAfterDelete(int *p) { |
185 | delete p; |
186 | f(p, p, p); // expected-warning{{Use of memory after it is freed}} |
187 | } |
188 | |
189 | void testUseRefArgAfterDelete(SomeClass &c) { |
190 | delete &c; |
191 | g(c); // expected-warning{{Use of memory after it is freed}} |
192 | } |
193 | |
194 | void testVariadicArgAfterDelete() { |
195 | SomeClass c; |
196 | int *p = new int; |
197 | delete p; |
198 | g(c, 0, p); // expected-warning{{Use of memory after it is freed}} |
199 | } |
200 | |
201 | void testUseMethodArgAfterDelete(int *p) { |
202 | SomeClass *c = new SomeClass; |
203 | delete p; |
204 | c->f(p); // expected-warning{{Use of memory after it is freed}} |
205 | } |
206 | |
207 | void testUseThisAfterDelete() { |
208 | SomeClass *c = new SomeClass; |
209 | delete c; |
210 | c->f(0); // expected-warning{{Use of memory after it is freed}} |
211 | } |
212 | |
213 | void testDoubleDelete() { |
214 | int *p = new int; |
215 | delete p; |
216 | delete p; // expected-warning{{Attempt to free released memory}} |
217 | } |
218 | |
219 | void testExprDeleteArg() { |
220 | int i; |
221 | delete &i; // expected-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}} |
222 | } |
223 | |
224 | void testExprDeleteArrArg() { |
225 | int i; |
226 | delete[] &i; // expected-warning{{Argument to 'delete[]' is the address of the local variable 'i', which is not memory allocated by 'new[]'}} |
227 | } |
228 | |
229 | void testAllocDeallocNames() { |
230 | int *p = new(std::nothrow) int[1]; |
231 | delete[] (++p); |
232 | #ifndef TEST_INLINABLE_ALLOCATORS |
233 | // expected-warning@-2{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}} |
234 | #endif |
235 | } |
236 | |
237 | //-------------------------------- |
238 | // Test escape of newed const pointer. Note, a const pointer can be deleted. |
239 | //-------------------------------- |
240 | struct StWithConstPtr { |
241 | const int *memp; |
242 | }; |
243 | void escape(const int &x); |
244 | void escapeStruct(const StWithConstPtr &x); |
245 | void escapePtr(const StWithConstPtr *x); |
246 | void escapeVoidPtr(const void *x); |
247 | |
248 | void testConstEscape() { |
249 | int *p = new int(1); |
250 | escape(*p); |
251 | } // no-warning |
252 | |
253 | void testConstEscapeStruct() { |
254 | StWithConstPtr *St = new StWithConstPtr(); |
255 | escapeStruct(*St); |
256 | } // no-warning |
257 | |
258 | void testConstEscapeStructPtr() { |
259 | StWithConstPtr *St = new StWithConstPtr(); |
260 | escapePtr(St); |
261 | } // no-warning |
262 | |
263 | void testConstEscapeMember() { |
264 | StWithConstPtr St; |
265 | St.memp = new int(2); |
266 | escapeVoidPtr(St.memp); |
267 | } // no-warning |
268 | |
269 | void testConstEscapePlacementNew() { |
270 | int *x = (int *)malloc(sizeof(int)); |
271 | void *y = new (x) int; |
272 | escapeVoidPtr(y); |
273 | } // no-warning |
274 | |
275 | //============== Test Uninitialized delete delete[]======================== |
276 | void testUninitDelete() { |
277 | int *x; |
278 | int * y = new int; |
279 | delete y; |
280 | delete x; // expected-warning{{Argument to 'delete' is uninitialized}} |
281 | } |
282 | |
283 | void testUninitDeleteArray() { |
284 | int *x; |
285 | int * y = new int[5]; |
286 | delete[] y; |
287 | delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}} |
288 | } |
289 | |
290 | void testUninitFree() { |
291 | int *x; |
292 | free(x); // expected-warning{{1st function call argument is an uninitialized value}} |
293 | } |
294 | |
295 | void testUninitDeleteSink() { |
296 | int *x; |
297 | delete x; // expected-warning{{Argument to 'delete' is uninitialized}} |
298 | (*(volatile int *)0 = 1); // no warn |
299 | } |
300 | |
301 | void testUninitDeleteArraySink() { |
302 | int *x; |
303 | delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}} |
304 | (*(volatile int *)0 = 1); // no warn |
305 | } |
306 | |
307 | namespace reference_count { |
308 | class control_block { |
309 | unsigned count; |
310 | public: |
311 | control_block() : count(0) {} |
312 | void retain() { ++count; } |
313 | int release() { return --count; } |
314 | }; |
315 | |
316 | template <typename T> |
317 | class shared_ptr { |
318 | T *p; |
319 | control_block *control; |
320 | |
321 | public: |
322 | shared_ptr() : p(0), control(0) {} |
323 | explicit shared_ptr(T *p) : p(p), control(new control_block) { |
324 | control->retain(); |
325 | } |
326 | shared_ptr(shared_ptr &other) : p(other.p), control(other.control) { |
327 | if (control) |
328 | control->retain(); |
329 | } |
330 | ~shared_ptr() { |
331 | if (control && control->release() == 0) { |
332 | delete p; |
333 | delete control; |
334 | } |
335 | }; |
336 | |
337 | T &operator *() { |
338 | return *p; |
339 | }; |
340 | |
341 | void swap(shared_ptr &other) { |
342 | T *tmp = p; |
343 | p = other.p; |
344 | other.p = tmp; |
345 | |
346 | control_block *ctrlTmp = control; |
347 | control = other.control; |
348 | other.control = ctrlTmp; |
349 | } |
350 | }; |
351 | |
352 | void testSingle() { |
353 | shared_ptr<int> a(new int); |
354 | *a = 1; |
355 | } |
356 | |
357 | void testDouble() { |
358 | shared_ptr<int> a(new int); |
359 | shared_ptr<int> b = a; |
360 | *a = 1; |
361 | } |
362 | |
363 | void testInvalidated() { |
364 | shared_ptr<int> a(new int); |
365 | shared_ptr<int> b = a; |
366 | *a = 1; |
367 | |
368 | extern void use(shared_ptr<int> &); |
369 | use(b); |
370 | } |
371 | |
372 | void testNestedScope() { |
373 | shared_ptr<int> a(new int); |
374 | { |
375 | shared_ptr<int> b = a; |
376 | } |
377 | *a = 1; |
378 | } |
379 | |
380 | void testSwap() { |
381 | shared_ptr<int> a(new int); |
382 | shared_ptr<int> b; |
383 | shared_ptr<int> c = a; |
384 | shared_ptr<int>(c).swap(b); |
385 | } |
386 | |
387 | void testUseAfterFree() { |
388 | int *p = new int; |
389 | { |
390 | shared_ptr<int> a(p); |
391 | shared_ptr<int> b = a; |
392 | } |
393 | |
394 | // FIXME: We should get a warning here, but we don't because we've |
395 | // conservatively modeled ~shared_ptr. |
396 | *p = 1; |
397 | } |
398 | } |
399 | |
400 | // Test double delete |
401 | class DerefClass{ |
402 | public: |
403 | int *x; |
404 | DerefClass() {} |
405 | ~DerefClass() {*x = 1;} |
406 | }; |
407 | |
408 | void testDoubleDeleteClassInstance() { |
409 | DerefClass *foo = new DerefClass(); |
410 | delete foo; |
411 | delete foo; // expected-warning {{Attempt to delete released memory}} |
412 | } |
413 | |
414 | class EmptyClass{ |
415 | public: |
416 | EmptyClass() {} |
417 | ~EmptyClass() {} |
418 | }; |
419 | |
420 | void testDoubleDeleteEmptyClass() { |
421 | EmptyClass *foo = new EmptyClass(); |
422 | delete foo; |
423 | delete foo; // expected-warning {{Attempt to delete released memory}} |
424 | } |
425 | |
426 | struct Base { |
427 | virtual ~Base() {} |
428 | }; |
429 | |
430 | struct Derived : Base { |
431 | }; |
432 | |
433 | Base *allocate() { |
434 | return new Derived; |
435 | } |
436 | |
437 | void shouldNotReportLeak() { |
438 | Derived *p = (Derived *)allocate(); |
439 | delete p; |
440 | } |
441 | |