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 | |
5 | void clang_analyzer_eval(bool); |
6 | |
7 | typedef __typeof__(sizeof(int)) size_t; |
8 | extern "C" void *malloc(size_t); |
9 | extern "C" void free(void *); |
10 | |
11 | int someGlobal; |
12 | |
13 | class SomeClass { |
14 | public: |
15 | void f(int *p); |
16 | }; |
17 | |
18 | void 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 | |
31 | void *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 | |
43 | void *operator new(size_t, size_t, int *); |
44 | void *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 | |
54 | void *operator new(size_t, void *, void *); |
55 | void *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 | |
64 | void 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 | |
78 | struct PtrWrapper { |
79 | int *x; |
80 | |
81 | PtrWrapper(int *input) : x(input) {} |
82 | }; |
83 | |
84 | PtrWrapper *testNewInvalidation() { |
85 | // Ensure that we don't consider this a leak. |
86 | return new PtrWrapper(static_cast<int *>(malloc(4))); // no-warning |
87 | } |
88 | |
89 | void 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 | |
94 | int **testNewInvalidationScalar() { |
95 | // Ensure that we don't consider this a leak. |
96 | return new (int *)(static_cast<int *>(malloc(4))); // no-warning |
97 | } |
98 | |
99 | void 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 | |
104 | void 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 | |
111 | void 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. |
124 | void 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. |
139 | void 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 | |
144 | void 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 | |
150 | void 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 | |
156 | void 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 | |
162 | void 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 | |
168 | void testUsingThisAfterDelete() { |
169 | SomeClass *c = new SomeClass; |
170 | delete c; |
171 | c->f(0); // no-warning |
172 | } |
173 | |
174 | void 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 | |
188 | int 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 | |
200 | int 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 |
211 | class IntPair{ |
212 | public: |
213 | int x; |
214 | int y; |
215 | IntPair() {}; |
216 | ~IntPair() {x = x/y;}; //expected-warning {{Division by zero}} |
217 | }; |
218 | |
219 | void 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. |
227 | class DerefClass{ |
228 | public: |
229 | int *x; |
230 | DerefClass() {}; |
231 | ~DerefClass() {*x = 1;}; //expected-warning {{Dereference of null pointer (loaded from field 'x')}} |
232 | }; |
233 | |
234 | void testDestCall(DerefClass *arg) { |
235 | delete arg; |
236 | } |
237 | |
238 | void 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 |
245 | void abort(void) __attribute__((noreturn)); |
246 | |
247 | class NoReturnDtor { |
248 | public: |
249 | NoReturnDtor() {} |
250 | ~NoReturnDtor() {abort();} |
251 | }; |
252 | |
253 | void test_delete_dtor_LocalVar() { |
254 | NoReturnDtor test; |
255 | delete &test; // no warn or crash |
256 | } |
257 | |
258 | class DerivedNoReturn:public NoReturnDtor { |
259 | public: |
260 | DerivedNoReturn() {}; |
261 | ~DerivedNoReturn() {}; |
262 | }; |
263 | |
264 | void 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 |
271 | void test_var_delete() { |
272 | int *v = new int; |
273 | delete v; // no crash/warn |
274 | clang_analyzer_eval(true); // expected-warning{{TRUE}} |
275 | } |
276 | |
277 | void 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 | |
295 | void testDeleteNull() { |
296 | NoReturnDtor *foo = 0; |
297 | delete foo; // should not call destructor, checked below |
298 | clang_analyzer_eval(true); // expected-warning{{TRUE}} |
299 | } |
300 | |
301 | void 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 | |
308 | void deleteArg(NoReturnDtor *test) { |
309 | delete test; |
310 | } |
311 | |
312 | void testNulldtorArg() { |
313 | NoReturnDtor *p = 0; |
314 | deleteArg(p); |
315 | clang_analyzer_eval(true); // expected-warning{{TRUE}} |
316 | } |
317 | |
318 | void testDeleteUnknown(NoReturnDtor *foo) { |
319 | delete foo; // should assume non-null and call noreturn destructor |
320 | clang_analyzer_eval(true); // no-warning |
321 | } |
322 | |
323 | void testArrayNull() { |
324 | NoReturnDtor *fooArray = 0; |
325 | delete[] fooArray; // should not call destructor, checked below |
326 | clang_analyzer_eval(true); // expected-warning{{TRUE}} |
327 | } |
328 | |
329 | void 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 |
337 | class InvalidateDestTest { |
338 | public: |
339 | int x; |
340 | int *y; |
341 | ~InvalidateDestTest(); |
342 | }; |
343 | |
344 | int 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 | |