1// RUN: %clang_analyze_cc1 -analyzer-store=region -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-output=text -verify %s
2
3typedef unsigned int NSUInteger;
4typedef __typeof__(sizeof(int)) size_t;
5
6void *malloc(size_t);
7void *calloc(size_t nmemb, size_t size);
8void free(void *);
9
10void clang_analyzer_eval(int);
11
12struct s {
13  int data;
14};
15
16struct s global;
17
18void g(int);
19
20void 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.
30struct TestUninit { int x; int y; };
31struct TestUninit test_uninit_aux();
32void test_unit_aux2(int);
33void 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}
41void 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}
47void 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
54void 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
60extern void test_uninit_struct_arg_aux(struct TestUninit arg);
61void 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
70void 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.
78void 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
87void test_PR10163(float);
88void 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.
95void PR10163_default_initialized_arrays(void) {
96  float x[2] = {0};
97  test_PR10163(x[1]); // no-warning
98}
99
100struct MyStr {
101  int x;
102  int y;
103};
104void 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}
109int 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
122NSUInteger 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
142typedef struct {
143  float x;
144  float y;
145  float z;
146} Point;
147typedef struct {
148  Point origin;
149  int size;
150} Circle;
151
152Point 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
160void 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 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
180void 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
191typedef struct {
192  int x;
193  int y;
194  int z;
195} IntPoint;
196typedef struct {
197  IntPoint origin;
198  int size;
199} IntCircle;
200
201IntPoint 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
209void 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 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
247void 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
264void 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
276typedef struct {
277  int x;
278  int y;
279} IntPoint2D;
280typedef struct {
281  IntPoint2D origin;
282  int size;
283} IntCircle2D;
284
285IntPoint2D makeIntPoint2D(int x, int y) {
286  IntPoint2D result;
287  result.x = x;
288  result.y = y;
289  return result;
290}
291
292void 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
303void 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
313void 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{{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
341void 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
355void testSmallStructBitfields() {
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
371void testSmallStructBitfieldsFirstUndef() {
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
386void testSmallStructBitfieldsSecondUndef() {
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
401void testSmallStructBitfieldsFirstUnnamed() {
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
418void testSmallStructBitfieldsSecondUnnamed() {
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}
434