1 | // RUN: %clang_analyze_cc1 -analyzer-store=region -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-output=text -verify %s |
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 | |
20 | void f4() { |
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; }; |
31 | struct TestUninit test_uninit_aux(); |
32 | void test_unit_aux2(int); |
33 | void test_uninit_pos() { |
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 | } |
41 | void test_uninit_pos_2() { |
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 | } |
47 | void test_uninit_pos_3() { |
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 | |
54 | void test_uninit_neg() { |
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); |
61 | void test_uninit_struct_arg() { |
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. |
78 | void rdar_7780304() { |
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 | |
160 | void PR14765_test() { |
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 the condition is false}} |
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 | |
209 | void PR14765_test_int() { |
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 the condition is false}} |
223 | // expected-note@-1{{Taking false branch}} |
224 | // expected-note@-2{{Assuming the condition is false}} |
225 | // expected-note@-3{{Taking false branch}} |
226 | // expected-note@-4{{Assuming the condition is false}} |
227 | // expected-note@-5{{Taking false branch}} |
228 | // expected-note@-6{{Assuming the condition is false}} |
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 | |
292 | void testSmallStructsCopiedPerField() { |
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 | |
303 | void testLargeStructsNotCopiedPerField() { |
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 | |
313 | void testSmallStructInLargerStruct() { |
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{{Taking false branch}} |
325 | // expected-note@-1{{Taking false branch}} |
326 | // expected-note@-2{{Taking false branch}} |
327 | |
328 | clang_analyzer_eval(testObj->size == 0); // expected-warning{{TRUE}} |
329 | // expected-note@-1{{TRUE}} |
330 | clang_analyzer_eval(testObj->origin.x == 1); // expected-warning{{TRUE}} |
331 | // expected-note@-1{{TRUE}} |
332 | clang_analyzer_eval(testObj->origin.y == 2); // expected-warning{{TRUE}} |
333 | // expected-note@-1{{TRUE}} |
334 | |
335 | free(testObj); |
336 | } |
337 | |
338 | void testCopySmallStructIntoArgument(IntCircle2D *testObj) { |
339 | int oldSize = testObj->size; |
340 | clang_analyzer_eval(testObj->size == oldSize); // expected-warning{{TRUE}} |
341 | // expected-note@-1{{TRUE}} |
342 | |
343 | testObj->origin = makeIntPoint2D(1, 2); |
344 | clang_analyzer_eval(testObj->size == oldSize); // expected-warning{{TRUE}} |
345 | // expected-note@-1{{TRUE}} |
346 | clang_analyzer_eval(testObj->origin.x == 1); // expected-warning{{TRUE}} |
347 | // expected-note@-1{{TRUE}} |
348 | clang_analyzer_eval(testObj->origin.y == 2); // expected-warning{{TRUE}} |
349 | // expected-note@-1{{TRUE}} |
350 | } |
351 | |
352 | void testSmallStructBitfields() { |
353 | struct { |
354 | int x : 4; |
355 | int y : 4; |
356 | } a, b; |
357 | |
358 | a.x = 1; |
359 | a.y = 2; |
360 | |
361 | b = a; |
362 | clang_analyzer_eval(b.x == 1); // expected-warning{{TRUE}} |
363 | // expected-note@-1{{TRUE}} |
364 | clang_analyzer_eval(b.y == 2); // expected-warning{{TRUE}} |
365 | // expected-note@-1{{TRUE}} |
366 | } |
367 | |
368 | void testSmallStructBitfieldsFirstUndef() { |
369 | struct { |
370 | int x : 4; |
371 | int y : 4; |
372 | } a, b; |
373 | |
374 | a.y = 2; |
375 | |
376 | b = a; |
377 | clang_analyzer_eval(b.y == 2); // expected-warning{{TRUE}} |
378 | // expected-note@-1{{TRUE}} |
379 | clang_analyzer_eval(b.x == 1); // expected-warning{{garbage}} |
380 | // expected-note@-1{{garbage}} |
381 | } |
382 | |
383 | void testSmallStructBitfieldsSecondUndef() { |
384 | struct { |
385 | int x : 4; |
386 | int y : 4; |
387 | } a, b; |
388 | |
389 | a.x = 1; |
390 | |
391 | b = a; |
392 | clang_analyzer_eval(b.x == 1); // expected-warning{{TRUE}} |
393 | // expected-note@-1{{TRUE}} |
394 | clang_analyzer_eval(b.y == 2); // expected-warning{{garbage}} |
395 | // expected-note@-1{{garbage}} |
396 | } |
397 | |
398 | void testSmallStructBitfieldsFirstUnnamed() { |
399 | struct { |
400 | int : 4; |
401 | int y : 4; |
402 | } a, b, c; // expected-note{{'c' initialized here}} |
403 | |
404 | a.y = 2; |
405 | |
406 | b = a; |
407 | clang_analyzer_eval(b.y == 2); // expected-warning{{TRUE}} |
408 | // expected-note@-1{{TRUE}} |
409 | |
410 | b = c; // expected-note{{Uninitialized value stored to 'b.y'}} |
411 | clang_analyzer_eval(b.y == 2); // expected-warning{{garbage}} |
412 | // expected-note@-1{{garbage}} |
413 | } |
414 | |
415 | void testSmallStructBitfieldsSecondUnnamed() { |
416 | struct { |
417 | int x : 4; |
418 | int : 4; |
419 | } a, b, c; // expected-note{{'c' initialized here}} |
420 | |
421 | a.x = 1; |
422 | |
423 | b = a; |
424 | clang_analyzer_eval(b.x == 1); // expected-warning{{TRUE}} |
425 | // expected-note@-1{{TRUE}} |
426 | |
427 | b = c; // expected-note{{Uninitialized value stored to 'b.x'}} |
428 | clang_analyzer_eval(b.x == 1); // expected-warning{{garbage}} |
429 | // expected-note@-1{{garbage}} |
430 | } |
431 | |