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