236
|
1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-output=text -verify %s
|
150
|
2
|
|
3 typedef unsigned int NSUInteger;
|
|
4 typedef __typeof__(sizeof(int)) size_t;
|
|
5
|
|
6 void *malloc(size_t);
|
|
7 void *calloc(size_t nmemb, size_t size);
|
|
8 void free(void *);
|
|
9
|
|
10 void clang_analyzer_eval(int);
|
|
11
|
|
12 struct s {
|
|
13 int data;
|
|
14 };
|
|
15
|
|
16 struct s global;
|
|
17
|
|
18 void g(int);
|
|
19
|
236
|
20 void f4(void) {
|
150
|
21 int a;
|
|
22 if (global.data == 0)
|
|
23 a = 3;
|
|
24 if (global.data == 0) // When the true branch is feasible 'a = 3'.
|
|
25 g(a); // no-warning
|
|
26 }
|
|
27
|
|
28
|
|
29 // Test uninitialized value due to part of the structure being uninitialized.
|
|
30 struct TestUninit { int x; int y; };
|
236
|
31 struct TestUninit test_uninit_aux(void);
|
150
|
32 void test_unit_aux2(int);
|
236
|
33 void test_uninit_pos(void) {
|
150
|
34 struct TestUninit v1 = { 0, 0 };
|
|
35 struct TestUninit v2 = test_uninit_aux();
|
|
36 int z; // expected-note{{'z' declared without an initial value}}
|
|
37 v1.y = z; // expected-warning{{Assigned value is garbage or undefined}}
|
|
38 // expected-note@-1{{Assigned value is garbage or undefined}}
|
|
39 test_unit_aux2(v2.x + v1.y);
|
|
40 }
|
236
|
41 void test_uninit_pos_2(void) {
|
150
|
42 struct TestUninit v1 = { 0, 0 };
|
|
43 struct TestUninit v2;
|
|
44 test_unit_aux2(v2.x + v1.y); // expected-warning{{The left operand of '+' is a garbage value}}
|
|
45 // expected-note@-1{{The left operand of '+' is a garbage value}}
|
|
46 }
|
236
|
47 void test_uninit_pos_3(void) {
|
150
|
48 struct TestUninit v1 = { 0, 0 };
|
|
49 struct TestUninit v2;
|
|
50 test_unit_aux2(v1.y + v2.x); // expected-warning{{The right operand of '+' is a garbage value}}
|
|
51 // expected-note@-1{{The right operand of '+' is a garbage value}}
|
|
52 }
|
|
53
|
236
|
54 void test_uninit_neg(void) {
|
150
|
55 struct TestUninit v1 = { 0, 0 };
|
|
56 struct TestUninit v2 = test_uninit_aux();
|
|
57 test_unit_aux2(v2.x + v1.y);
|
|
58 }
|
|
59
|
|
60 extern void test_uninit_struct_arg_aux(struct TestUninit arg);
|
236
|
61 void test_uninit_struct_arg(void) {
|
150
|
62 struct TestUninit x; // expected-note{{'x' initialized here}}
|
|
63 test_uninit_struct_arg_aux(x); // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}}
|
|
64 // expected-note@-1{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}}
|
|
65 }
|
|
66
|
|
67 @interface Foo
|
|
68 - (void) passVal:(struct TestUninit)arg;
|
|
69 @end
|
|
70 void testFoo(Foo *o) {
|
|
71 struct TestUninit x; // expected-note{{'x' initialized here}}
|
|
72 [o passVal:x]; // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}}
|
|
73 // expected-note@-1{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}}
|
|
74 }
|
|
75
|
|
76 // Test case from <rdar://problem/7780304>. That shows an uninitialized value
|
|
77 // being used in the LHS of a compound assignment.
|
236
|
78 void rdar_7780304(void) {
|
150
|
79 typedef struct s_r7780304 { int x; } s_r7780304;
|
|
80 s_r7780304 b;
|
|
81 b.x |= 1; // expected-warning{{The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage}}
|
|
82 // expected-note@-1{{The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage}}
|
|
83 }
|
|
84
|
|
85
|
|
86 // The flip side of PR10163 -- float arrays that are actually uninitialized
|
|
87 void test_PR10163(float);
|
|
88 void PR10163 (void) {
|
|
89 float x[2];
|
|
90 test_PR10163(x[1]); // expected-warning{{uninitialized value}}
|
|
91 // expected-note@-1{{1st function call argument is an uninitialized value}}
|
|
92 }
|
|
93
|
|
94 // PR10163 -- don't warn for default-initialized float arrays.
|
|
95 void PR10163_default_initialized_arrays(void) {
|
|
96 float x[2] = {0};
|
|
97 test_PR10163(x[1]); // no-warning
|
|
98 }
|
|
99
|
|
100 struct MyStr {
|
|
101 int x;
|
|
102 int y;
|
|
103 };
|
|
104 void swap(struct MyStr *To, struct MyStr *From) {
|
|
105 // This is not really a swap but close enough for our test.
|
|
106 To->x = From->x;
|
|
107 To->y = From->y; // expected-note{{Uninitialized value stored to field 'y'}}
|
|
108 }
|
|
109 int test_undefined_member_assignment_in_swap(struct MyStr *s2) {
|
|
110 struct MyStr s1;
|
|
111 s1.x = 5;
|
|
112 swap(s2, &s1); // expected-note{{Calling 'swap'}}
|
|
113 // expected-note@-1{{Returning from 'swap'}}
|
|
114 return s2->y; // expected-warning{{Undefined or garbage value returned to caller}}
|
|
115 // expected-note@-1{{Undefined or garbage value returned to caller}}
|
|
116 }
|
|
117
|
|
118 @interface A
|
|
119 - (NSUInteger)foo;
|
|
120 @end
|
|
121
|
|
122 NSUInteger f8(A* x){
|
|
123 const NSUInteger n = [x foo];
|
|
124 int* bogus;
|
|
125
|
|
126 if (n > 0) { // tests const cast transfer function logic
|
|
127 NSUInteger i;
|
|
128
|
|
129 for (i = 0; i < n; ++i)
|
|
130 bogus = 0;
|
|
131
|
|
132 if (bogus) // no-warning
|
|
133 return n+1;
|
|
134 }
|
|
135
|
|
136 return n;
|
|
137 }
|
|
138
|
|
139
|
|
140
|
|
141
|
|
142 typedef struct {
|
|
143 float x;
|
|
144 float y;
|
|
145 float z;
|
|
146 } Point;
|
|
147 typedef struct {
|
|
148 Point origin;
|
|
149 int size;
|
|
150 } Circle;
|
|
151
|
|
152 Point makePoint(float x, float y) {
|
|
153 Point result;
|
|
154 result.x = x;
|
|
155 result.y = y;
|
|
156 result.z = 0.0;
|
|
157 return result;
|
|
158 }
|
|
159
|
236
|
160 void PR14765_test(void) {
|
150
|
161 Circle *testObj = calloc(sizeof(Circle), 1);
|
|
162
|
|
163 clang_analyzer_eval(testObj->size == 0); // expected-warning{{TRUE}}
|
|
164 // expected-note@-1{{TRUE}}
|
|
165
|
|
166 testObj->origin = makePoint(0.0, 0.0);
|
|
167 if (testObj->size > 0) { ; } // expected-note{{Assuming field 'size' is <= 0}}
|
|
168 // expected-note@-1{{Taking false branch}}
|
|
169
|
|
170 // FIXME: Assigning to 'testObj->origin' kills the default binding for the
|
|
171 // whole region, meaning that we've forgotten that testObj->size should also
|
|
172 // default to 0. Tracked by <rdar://problem/12701038>.
|
|
173 // This should be TRUE.
|
|
174 clang_analyzer_eval(testObj->size == 0); // expected-warning{{UNKNOWN}}
|
|
175 // expected-note@-1{{UNKNOWN}}
|
|
176
|
|
177 free(testObj);
|
|
178 }
|
|
179
|
|
180 void PR14765_argument(Circle *testObj) {
|
|
181 int oldSize = testObj->size;
|
|
182 clang_analyzer_eval(testObj->size == oldSize); // expected-warning{{TRUE}}
|
|
183 // expected-note@-1{{TRUE}}
|
|
184
|
|
185 testObj->origin = makePoint(0.0, 0.0);
|
|
186 clang_analyzer_eval(testObj->size == oldSize); // expected-warning{{TRUE}}
|
|
187 // expected-note@-1{{TRUE}}
|
|
188 }
|
|
189
|
|
190
|
|
191 typedef struct {
|
|
192 int x;
|
|
193 int y;
|
|
194 int z;
|
|
195 } IntPoint;
|
|
196 typedef struct {
|
|
197 IntPoint origin;
|
|
198 int size;
|
|
199 } IntCircle;
|
|
200
|
|
201 IntPoint makeIntPoint(int x, int y) {
|
|
202 IntPoint result;
|
|
203 result.x = x;
|
|
204 result.y = y;
|
|
205 result.z = 0;
|
|
206 return result;
|
|
207 }
|
|
208
|
236
|
209 void PR14765_test_int(void) {
|
150
|
210 IntCircle *testObj = calloc(sizeof(IntCircle), 1);
|
|
211
|
|
212 clang_analyzer_eval(testObj->size == 0); // expected-warning{{TRUE}}
|
|
213 // expected-note@-1{{TRUE}}
|
|
214 clang_analyzer_eval(testObj->origin.x == 0); // expected-warning{{TRUE}}
|
|
215 // expected-note@-1{{TRUE}}
|
|
216 clang_analyzer_eval(testObj->origin.y == 0); // expected-warning{{TRUE}}
|
|
217 // expected-note@-1{{TRUE}}
|
|
218 clang_analyzer_eval(testObj->origin.z == 0); // expected-warning{{TRUE}}
|
|
219 // expected-note@-1{{TRUE}}
|
|
220
|
|
221 testObj->origin = makeIntPoint(1, 2);
|
|
222 if (testObj->size > 0) { ; } // expected-note{{Assuming field 'size' is <= 0}}
|
|
223 // expected-note@-1{{Taking false branch}}
|
|
224 // expected-note@-2{{Assuming field 'size' is <= 0}}
|
|
225 // expected-note@-3{{Taking false branch}}
|
|
226 // expected-note@-4{{Assuming field 'size' is <= 0}}
|
|
227 // expected-note@-5{{Taking false branch}}
|
|
228 // expected-note@-6{{Assuming field 'size' is <= 0}}
|
|
229 // expected-note@-7{{Taking false branch}}
|
|
230
|
|
231 // FIXME: Assigning to 'testObj->origin' kills the default binding for the
|
|
232 // whole region, meaning that we've forgotten that testObj->size should also
|
|
233 // default to 0. Tracked by <rdar://problem/12701038>.
|
|
234 // This should be TRUE.
|
|
235 clang_analyzer_eval(testObj->size == 0); // expected-warning{{UNKNOWN}}
|
|
236 // expected-note@-1{{UNKNOWN}}
|
|
237 clang_analyzer_eval(testObj->origin.x == 1); // expected-warning{{TRUE}}
|
|
238 // expected-note@-1{{TRUE}}
|
|
239 clang_analyzer_eval(testObj->origin.y == 2); // expected-warning{{TRUE}}
|
|
240 // expected-note@-1{{TRUE}}
|
|
241 clang_analyzer_eval(testObj->origin.z == 0); // expected-warning{{TRUE}}
|
|
242 // expected-note@-1{{TRUE}}
|
|
243
|
|
244 free(testObj);
|
|
245 }
|
|
246
|
|
247 void PR14765_argument_int(IntCircle *testObj) {
|
|
248 int oldSize = testObj->size;
|
|
249 clang_analyzer_eval(testObj->size == oldSize); // expected-warning{{TRUE}}
|
|
250 // expected-note@-1{{TRUE}}
|
|
251
|
|
252 testObj->origin = makeIntPoint(1, 2);
|
|
253 clang_analyzer_eval(testObj->size == oldSize); // expected-warning{{TRUE}}
|
|
254 // expected-note@-1{{TRUE}}
|
|
255 clang_analyzer_eval(testObj->origin.x == 1); // expected-warning{{TRUE}}
|
|
256 // expected-note@-1{{TRUE}}
|
|
257 clang_analyzer_eval(testObj->origin.y == 2); // expected-warning{{TRUE}}
|
|
258 // expected-note@-1{{TRUE}}
|
|
259 clang_analyzer_eval(testObj->origin.z == 0); // expected-warning{{TRUE}}
|
|
260 // expected-note@-1{{TRUE}}
|
|
261 }
|
|
262
|
|
263
|
|
264 void rdar13292559(Circle input) {
|
|
265 extern void useCircle(Circle);
|
|
266
|
|
267 Circle obj = input;
|
|
268 useCircle(obj); // no-warning
|
|
269
|
|
270 // This generated an "uninitialized 'size' field" warning for a (short) while.
|
|
271 obj.origin = makePoint(0.0, 0.0);
|
|
272 useCircle(obj); // no-warning
|
|
273 }
|
|
274
|
|
275
|
|
276 typedef struct {
|
|
277 int x;
|
|
278 int y;
|
|
279 } IntPoint2D;
|
|
280 typedef struct {
|
|
281 IntPoint2D origin;
|
|
282 int size;
|
|
283 } IntCircle2D;
|
|
284
|
|
285 IntPoint2D makeIntPoint2D(int x, int y) {
|
|
286 IntPoint2D result;
|
|
287 result.x = x;
|
|
288 result.y = y;
|
|
289 return result;
|
|
290 }
|
|
291
|
236
|
292 void testSmallStructsCopiedPerField(void) {
|
150
|
293 IntPoint2D a;
|
|
294 a.x = 0;
|
|
295
|
|
296 IntPoint2D b = a;
|
|
297 extern void useInt(int);
|
|
298 useInt(b.x); // no-warning
|
|
299 useInt(b.y); // expected-warning{{uninitialized}}
|
|
300 // expected-note@-1{{uninitialized}}
|
|
301 }
|
|
302
|
236
|
303 void testLargeStructsNotCopiedPerField(void) {
|
150
|
304 IntPoint a;
|
|
305 a.x = 0;
|
|
306
|
|
307 IntPoint b = a;
|
|
308 extern void useInt(int);
|
|
309 useInt(b.x); // no-warning
|
|
310 useInt(b.y); // no-warning
|
|
311 }
|
|
312
|
236
|
313 void testSmallStructInLargerStruct(void) {
|
150
|
314 IntCircle2D *testObj = calloc(sizeof(IntCircle2D), 1);
|
|
315
|
|
316 clang_analyzer_eval(testObj->size == 0); // expected-warning{{TRUE}}
|
|
317 // expected-note@-1{{TRUE}}
|
|
318 clang_analyzer_eval(testObj->origin.x == 0); // expected-warning{{TRUE}}
|
|
319 // expected-note@-1{{TRUE}}
|
|
320 clang_analyzer_eval(testObj->origin.y == 0); // expected-warning{{TRUE}}
|
|
321 // expected-note@-1{{TRUE}}
|
|
322
|
|
323 testObj->origin = makeIntPoint2D(1, 2);
|
|
324 if (testObj->size > 0) { ; } // expected-note{{Field 'size' is <= 0}}
|
|
325 // expected-note@-1{{Taking false branch}}
|
|
326 // expected-note@-2{{Field 'size' is <= 0}}
|
|
327 // expected-note@-3{{Taking false branch}}
|
|
328 // expected-note@-4{{Field 'size' is <= 0}}
|
|
329 // expected-note@-5{{Taking false branch}}
|
|
330
|
|
331 clang_analyzer_eval(testObj->size == 0); // expected-warning{{TRUE}}
|
|
332 // expected-note@-1{{TRUE}}
|
|
333 clang_analyzer_eval(testObj->origin.x == 1); // expected-warning{{TRUE}}
|
|
334 // expected-note@-1{{TRUE}}
|
|
335 clang_analyzer_eval(testObj->origin.y == 2); // expected-warning{{TRUE}}
|
|
336 // expected-note@-1{{TRUE}}
|
|
337
|
|
338 free(testObj);
|
|
339 }
|
|
340
|
|
341 void testCopySmallStructIntoArgument(IntCircle2D *testObj) {
|
|
342 int oldSize = testObj->size;
|
|
343 clang_analyzer_eval(testObj->size == oldSize); // expected-warning{{TRUE}}
|
|
344 // expected-note@-1{{TRUE}}
|
|
345
|
|
346 testObj->origin = makeIntPoint2D(1, 2);
|
|
347 clang_analyzer_eval(testObj->size == oldSize); // expected-warning{{TRUE}}
|
|
348 // expected-note@-1{{TRUE}}
|
|
349 clang_analyzer_eval(testObj->origin.x == 1); // expected-warning{{TRUE}}
|
|
350 // expected-note@-1{{TRUE}}
|
|
351 clang_analyzer_eval(testObj->origin.y == 2); // expected-warning{{TRUE}}
|
|
352 // expected-note@-1{{TRUE}}
|
|
353 }
|
|
354
|
236
|
355 void testSmallStructBitfields(void) {
|
150
|
356 struct {
|
|
357 int x : 4;
|
|
358 int y : 4;
|
|
359 } a, b;
|
|
360
|
|
361 a.x = 1;
|
|
362 a.y = 2;
|
|
363
|
|
364 b = a;
|
|
365 clang_analyzer_eval(b.x == 1); // expected-warning{{TRUE}}
|
|
366 // expected-note@-1{{TRUE}}
|
|
367 clang_analyzer_eval(b.y == 2); // expected-warning{{TRUE}}
|
|
368 // expected-note@-1{{TRUE}}
|
|
369 }
|
|
370
|
236
|
371 void testSmallStructBitfieldsFirstUndef(void) {
|
150
|
372 struct {
|
|
373 int x : 4;
|
|
374 int y : 4;
|
|
375 } a, b;
|
|
376
|
|
377 a.y = 2;
|
|
378
|
|
379 b = a;
|
|
380 clang_analyzer_eval(b.y == 2); // expected-warning{{TRUE}}
|
|
381 // expected-note@-1{{TRUE}}
|
|
382 clang_analyzer_eval(b.x == 1); // expected-warning{{garbage}}
|
|
383 // expected-note@-1{{garbage}}
|
|
384 }
|
|
385
|
236
|
386 void testSmallStructBitfieldsSecondUndef(void) {
|
150
|
387 struct {
|
|
388 int x : 4;
|
|
389 int y : 4;
|
|
390 } a, b;
|
|
391
|
|
392 a.x = 1;
|
|
393
|
|
394 b = a;
|
|
395 clang_analyzer_eval(b.x == 1); // expected-warning{{TRUE}}
|
|
396 // expected-note@-1{{TRUE}}
|
|
397 clang_analyzer_eval(b.y == 2); // expected-warning{{garbage}}
|
|
398 // expected-note@-1{{garbage}}
|
|
399 }
|
|
400
|
236
|
401 void testSmallStructBitfieldsFirstUnnamed(void) {
|
150
|
402 struct {
|
|
403 int : 4;
|
|
404 int y : 4;
|
|
405 } a, b, c; // expected-note{{'c' initialized here}}
|
|
406
|
|
407 a.y = 2;
|
|
408
|
|
409 b = a;
|
|
410 clang_analyzer_eval(b.y == 2); // expected-warning{{TRUE}}
|
|
411 // expected-note@-1{{TRUE}}
|
|
412
|
|
413 b = c; // expected-note{{Uninitialized value stored to 'b.y'}}
|
|
414 clang_analyzer_eval(b.y == 2); // expected-warning{{garbage}}
|
|
415 // expected-note@-1{{garbage}}
|
|
416 }
|
|
417
|
236
|
418 void testSmallStructBitfieldsSecondUnnamed(void) {
|
150
|
419 struct {
|
|
420 int x : 4;
|
|
421 int : 4;
|
|
422 } a, b, c; // expected-note{{'c' initialized here}}
|
|
423
|
|
424 a.x = 1;
|
|
425
|
|
426 b = a;
|
|
427 clang_analyzer_eval(b.x == 1); // expected-warning{{TRUE}}
|
|
428 // expected-note@-1{{TRUE}}
|
|
429
|
|
430 b = c; // expected-note{{Uninitialized value stored to 'b.x'}}
|
|
431 clang_analyzer_eval(b.x == 1); // expected-warning{{garbage}}
|
|
432 // expected-note@-1{{garbage}}
|
|
433 }
|