Clang Project

clang_source_code/test/Analysis/NewDelete-checker-test.cpp
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
43typedef __typeof__(sizeof(int)) size_t;
44extern "C" void *malloc(size_t);
45extern "C" void free (void* ptr);
46int *global;
47
48//------------------
49// check for leaks
50//------------------
51
52//----- Standard non-placement operators
53void 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
60void 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
67void 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
74void 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
82void 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
91void 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
101void 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
114void 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
121struct PtrWrapper {
122  int *x;
123
124  PtrWrapper(int *input) : x(input) {}
125};
126
127void 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
136void testUseZeroAlloc1() {
137  int *p = (int *)operator new(0);
138  *p = 1; // expected-warning {{Use of zero-allocated memory}}
139  delete p;
140}
141
142int testUseZeroAlloc2() {
143  int *p = (int *)operator new[](0);
144  return p[0]; // expected-warning {{Use of zero-allocated memory}}
145  delete[] p;
146}
147
148void f(int);
149
150void 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
160class SomeClass {
161public:
162  void f(int *p);
163};
164
165void f(int *p1, int *p2 = 0, int *p3 = 0);
166void g(SomeClass &c, ...);
167
168void testUseFirstArgAfterDelete() {
169  int *p = new int;
170  delete p;
171  f(p); // expected-warning{{Use of memory after it is freed}}
172}
173
174void testUseMiddleArgAfterDelete(int *p) {
175  delete p;
176  f(0, p); // expected-warning{{Use of memory after it is freed}}
177}
178
179void testUseLastArgAfterDelete(int *p) {
180  delete p;
181  f(0, 0, p); // expected-warning{{Use of memory after it is freed}}
182}
183
184void testUseSeveralArgsAfterDelete(int *p) {
185  delete p;
186  f(p, p, p); // expected-warning{{Use of memory after it is freed}}
187}
188
189void testUseRefArgAfterDelete(SomeClass &c) {
190  delete &c;
191  g(c); // expected-warning{{Use of memory after it is freed}}
192}
193
194void 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
201void 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
207void testUseThisAfterDelete() {
208  SomeClass *c = new SomeClass;
209  delete c;
210  c->f(0); // expected-warning{{Use of memory after it is freed}}
211}
212
213void testDoubleDelete() {
214  int *p = new int;
215  delete p;
216  delete p; // expected-warning{{Attempt to free released memory}}
217}
218
219void 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
224void 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
229void 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//--------------------------------
240struct StWithConstPtr {
241  const int *memp;
242};
243void escape(const int &x);
244void escapeStruct(const StWithConstPtr &x);
245void escapePtr(const StWithConstPtr *x);
246void escapeVoidPtr(const void *x);
247
248void testConstEscape() {
249  int *p = new int(1);
250  escape(*p);
251} // no-warning
252
253void testConstEscapeStruct() {
254  StWithConstPtr *St = new StWithConstPtr();
255  escapeStruct(*St);
256} // no-warning
257
258void testConstEscapeStructPtr() {
259  StWithConstPtr *St = new StWithConstPtr();
260  escapePtr(St);
261} // no-warning
262
263void testConstEscapeMember() {
264  StWithConstPtr St;
265  St.memp = new int(2);
266  escapeVoidPtr(St.memp);
267} // no-warning
268
269void 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[]========================
276void testUninitDelete() {
277  int *x;
278  int * y = new int;
279  delete y;
280  delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
281}
282
283void 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
290void testUninitFree() {
291  int *x;
292  free(x); // expected-warning{{1st function call argument is an uninitialized value}}
293}
294
295void testUninitDeleteSink() {
296  int *x;
297  delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
298  (*(volatile int *)0 = 1); // no warn
299}
300
301void testUninitDeleteArraySink() {
302  int *x;
303  delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}
304  (*(volatile int *)0 = 1); // no warn
305}
306
307namespace 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
401class DerefClass{
402public:
403  int *x;
404  DerefClass() {}
405  ~DerefClass() {*x = 1;}
406};
407
408void testDoubleDeleteClassInstance() {
409  DerefClass *foo = new DerefClass();
410  delete foo;
411  delete foo; // expected-warning {{Attempt to delete released memory}}
412}
413
414class EmptyClass{
415public:
416  EmptyClass() {}
417  ~EmptyClass() {}
418};
419
420void testDoubleDeleteEmptyClass() {
421  EmptyClass *foo = new EmptyClass();
422  delete foo;
423  delete foo;  // expected-warning {{Attempt to delete released memory}}
424}
425
426struct Base {
427  virtual ~Base() {}
428};
429
430struct Derived : Base {
431};
432
433Base *allocate() {
434  return new Derived;
435}
436
437void shouldNotReportLeak() {
438  Derived *p = (Derived *)allocate();
439  delete p;
440}
441