Clang Project

clang_source_code/test/Analysis/new.cpp
1// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -std=c++11 -verify -analyzer-config eagerly-assume=false %s
2// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -std=c++11 -DTEST_INLINABLE_ALLOCATORS -verify -analyzer-config eagerly-assume=false %s
3#include "Inputs/system-header-simulator-cxx.h"
4
5void clang_analyzer_eval(bool);
6
7typedef __typeof__(sizeof(int)) size_t;
8extern "C" void *malloc(size_t);
9extern "C" void free(void *);
10
11int someGlobal;
12
13class SomeClass {
14public:
15  void f(int *p);
16};
17
18void testImplicitlyDeclaredGlobalNew() {
19  if (someGlobal != 0)
20    return;
21
22  // This used to crash because the global operator new is being implicitly
23  // declared and it does not have a valid source location. (PR13090)
24  void *x = ::operator new(0);
25  ::operator delete(x);
26
27  // Check that the new/delete did not invalidate someGlobal;
28  clang_analyzer_eval(someGlobal == 0); // expected-warning{{TRUE}}
29}
30
31void *testPlacementNew() {
32  int *x = (int *)malloc(sizeof(int));
33  *x = 1;
34  clang_analyzer_eval(*x == 1); // expected-warning{{TRUE}};
35
36  void *y = new (x) int;
37  clang_analyzer_eval(x == y); // expected-warning{{TRUE}};
38  clang_analyzer_eval(*x == 1); // expected-warning{{TRUE}};
39
40  return y;
41}
42
43void *operator new(size_t, size_t, int *);
44void *testCustomNew() {
45  int x[1] = {1};
46  clang_analyzer_eval(*x == 1); // expected-warning{{TRUE}};
47
48  void *y = new (0, x) int;
49  clang_analyzer_eval(*x == 1); // expected-warning{{UNKNOWN}};
50
51  return y; // no-warning
52}
53
54void *operator new(size_t, void *, void *);
55void *testCustomNewMalloc() {
56  int *x = (int *)malloc(sizeof(int));
57
58  // Should be no-warning (the custom allocator could have freed x).
59  void *y = new (0, x) int; // no-warning
60
61  return y;
62}
63
64void testScalarInitialization() {
65  int *n = new int(3);
66  clang_analyzer_eval(*n == 3); // expected-warning{{TRUE}}
67
68  new (n) int();
69  clang_analyzer_eval(*n == 0); // expected-warning{{TRUE}}
70
71  new (n) int{3};
72  clang_analyzer_eval(*n == 3); // expected-warning{{TRUE}}
73
74  new (n) int{};
75  clang_analyzer_eval(*n == 0); // expected-warning{{TRUE}}
76}
77
78struct PtrWrapper {
79  int *x;
80
81  PtrWrapper(int *input) : x(input) {}
82};
83
84PtrWrapper *testNewInvalidation() {
85  // Ensure that we don't consider this a leak.
86  return new PtrWrapper(static_cast<int *>(malloc(4))); // no-warning
87}
88
89void testNewInvalidationPlacement(PtrWrapper *w) {
90  // Ensure that we don't consider this a leak.
91  new (w) PtrWrapper(static_cast<int *>(malloc(4))); // no-warning
92}
93
94int **testNewInvalidationScalar() {
95  // Ensure that we don't consider this a leak.
96  return new (int *)(static_cast<int *>(malloc(4))); // no-warning
97}
98
99void testNewInvalidationScalarPlacement(int **p) {
100  // Ensure that we don't consider this a leak.
101  new (p) (int *)(static_cast<int *>(malloc(4))); // no-warning
102}
103
104void testCacheOut(PtrWrapper w) {
105  extern bool coin();
106  if (coin())
107    w.x = 0;
108  new (&w.x) (int*)(0); // we cache out here; don't crash
109}
110
111void testUseAfter(int *p) {
112  SomeClass *c = new SomeClass;
113  free(p);
114  c->f(p); // expected-warning{{Use of memory after it is freed}}
115  delete c;
116}
117
118//--------------------------------------------------------------------
119// Check for intersection with other checkers from MallocChecker.cpp 
120// bounded with unix.Malloc
121//--------------------------------------------------------------------
122
123// new/delete oparators are subjects of cplusplus.NewDelete.
124void testNewDeleteNoWarn() {
125  int i;
126  delete &i; // no-warning
127
128  int *p1 = new int;
129  delete ++p1; // no-warning
130
131  int *p2 = new int;
132  delete p2;
133  delete p2; // no-warning
134
135  int *p3 = new int; // no-warning
136}
137
138// unix.Malloc does not know about operators new/delete.
139void testDeleteMallocked() {
140  int *x = (int *)malloc(sizeof(int));
141  delete x; // FIXME: Should detect pointer escape and keep silent after 'delete' is modeled properly.
142} // expected-warning{{Potential leak of memory pointed to by 'x'}}
143
144void testDeleteOpAfterFree() {
145  int *p = (int *)malloc(sizeof(int));
146  free(p);
147  operator delete(p); // expected-warning{{Use of memory after it is freed}}
148}
149
150void testDeleteAfterFree() {
151  int *p = (int *)malloc(sizeof(int));
152  free(p);
153  delete p; // expected-warning{{Use of memory after it is freed}}
154}
155
156void testStandardPlacementNewAfterFree() {
157  int *p = (int *)malloc(sizeof(int));
158  free(p);
159  p = new(p) int; // expected-warning{{Use of memory after it is freed}}
160}
161
162void testCustomPlacementNewAfterFree() {
163  int *p = (int *)malloc(sizeof(int));
164  free(p);
165  p = new(0, p) int; // expected-warning{{Use of memory after it is freed}}
166}
167
168void testUsingThisAfterDelete() {
169  SomeClass *c = new SomeClass;
170  delete c;
171  c->f(0); // no-warning
172}
173
174void testAggregateNew() {
175  struct Point { int x, y; };
176  new Point{1, 2}; // no crash
177
178  Point p;
179  new (&p) Point{1, 2}; // no crash
180  clang_analyzer_eval(p.x == 1); // expected-warning{{TRUE}}
181  clang_analyzer_eval(p.y == 2); // expected-warning{{TRUE}}
182}
183
184//--------------------------------
185// Incorrectly-modelled behavior
186//--------------------------------
187
188int testNoInitialization() {
189  int *n = new int;
190
191  // Should warn that *n is uninitialized.
192  if (*n) { // no-warning
193    delete n;
194    return 0;
195  }
196  delete n;
197  return 1;
198}
199
200int testNoInitializationPlacement() {
201  int n;
202  new (&n) int;
203
204  if (n) { // expected-warning{{Branch condition evaluates to a garbage value}}
205    return 0;
206  }
207  return 1;
208}
209
210// Test modelling destructor call on call to delete
211class IntPair{
212public:
213  int x;
214  int y;
215  IntPair() {};
216  ~IntPair() {x = x/y;}; //expected-warning {{Division by zero}}
217};
218
219void testCallToDestructor() {
220  IntPair *b = new IntPair();
221  b->x = 1;
222  b->y = 0;
223  delete b; // This results in divide by zero in destructor
224}
225
226// Test Deleting a value that's passed as an argument.
227class DerefClass{
228public:
229  int *x;
230  DerefClass() {};
231  ~DerefClass() {*x = 1;}; //expected-warning {{Dereference of null pointer (loaded from field 'x')}}
232};
233
234void testDestCall(DerefClass *arg) {
235  delete arg;
236}
237
238void test_delete_dtor_Arg() {
239  DerefClass *pair = new DerefClass();
240  pair->x = 0;
241  testDestCall(pair);
242}
243
244//Deleting the address of a local variable, null pointer
245void abort(void) __attribute__((noreturn));
246
247class NoReturnDtor {
248public:
249  NoReturnDtor() {}
250  ~NoReturnDtor() {abort();}
251};
252
253void test_delete_dtor_LocalVar() {
254  NoReturnDtor test;
255  delete &test; // no warn or crash
256}
257
258class DerivedNoReturn:public NoReturnDtor {
259public:
260  DerivedNoReturn() {};
261  ~DerivedNoReturn() {};
262};
263
264void testNullDtorDerived() {
265  DerivedNoReturn *p = new DerivedNoReturn();
266  delete p; // Calls the base destructor which aborts, checked below
267  clang_analyzer_eval(true); // no warn
268}
269
270//Deleting a non-class pointer should not crash/warn
271void test_var_delete() {
272  int *v = new int;
273  delete v;  // no crash/warn
274  clang_analyzer_eval(true); // expected-warning{{TRUE}}
275}
276
277void test_array_delete() {
278  class C {
279  public:
280    ~C() {}
281  };
282
283  auto c1 = new C[2][3];
284  delete[] c1; // no-crash // no-warning
285
286  C c2[4];
287  // FIXME: Should warn.
288  delete[] &c2; // no-crash
289
290  C c3[7][6];
291  // FIXME: Should warn.
292  delete[] &c3; // no-crash
293}
294
295void testDeleteNull() {
296  NoReturnDtor *foo = 0;
297  delete foo; // should not call destructor, checked below
298  clang_analyzer_eval(true); // expected-warning{{TRUE}}
299}
300
301void testNullAssigneddtor() {
302  NoReturnDtor *p = 0;
303  NoReturnDtor *s = p;
304  delete s; // should not call destructor, checked below
305  clang_analyzer_eval(true); // expected-warning{{TRUE}}
306}
307
308void deleteArg(NoReturnDtor *test) {
309  delete test;
310}
311
312void testNulldtorArg() {
313  NoReturnDtor *p = 0;
314  deleteArg(p);
315  clang_analyzer_eval(true); // expected-warning{{TRUE}}
316}
317
318void testDeleteUnknown(NoReturnDtor *foo) {
319  delete foo; // should assume non-null and call noreturn destructor
320  clang_analyzer_eval(true); // no-warning
321}
322
323void testArrayNull() {
324  NoReturnDtor *fooArray = 0;
325  delete[] fooArray; // should not call destructor, checked below
326  clang_analyzer_eval(true); // expected-warning{{TRUE}}
327}
328
329void testArrayDestr() {
330  NoReturnDtor *p = new NoReturnDtor[2];
331  delete[] p; // Calls the base destructor which aborts, checked below
332   //TODO: clang_analyzer_eval should not be called
333  clang_analyzer_eval(true); // expected-warning{{TRUE}}
334}
335
336// Invalidate Region even in case of default destructor
337class InvalidateDestTest {
338public:
339  int x;
340  int *y;
341  ~InvalidateDestTest();
342};
343
344int test_member_invalidation() {
345
346  //test invalidation of member variable
347  InvalidateDestTest *test = new InvalidateDestTest();
348  test->x = 5;
349  int *k = &(test->x);
350  clang_analyzer_eval(*k == 5); // expected-warning{{TRUE}}
351  delete test;
352  clang_analyzer_eval(*k == 5); // expected-warning{{UNKNOWN}}
353
354  //test invalidation of member pointer
355  int localVar = 5;
356  test = new InvalidateDestTest();
357  test->y = &localVar;
358  delete test;
359  clang_analyzer_eval(localVar == 5); // expected-warning{{UNKNOWN}}
360
361  // Test aray elements are invalidated.
362  int Var1 = 5;
363  int Var2 = 5;
364  InvalidateDestTest *a = new InvalidateDestTest[2];
365  a[0].y = &Var1;
366  a[1].y = &Var2;
367  delete[] a;
368  clang_analyzer_eval(Var1 == 5); // expected-warning{{UNKNOWN}}
369  clang_analyzer_eval(Var2 == 5); // expected-warning{{UNKNOWN}}
370  return 0;
371}
372