xref: /llvm-project/clang/test/Analysis/array-init-loop.cpp (revision a917ae0b4fc0d792ee0e2c512c4ea539f98e1204)
1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++17 -verify %s
2 
3 void clang_analyzer_eval(bool);
4 
5 void array_init() {
6   int arr[] = {1, 2, 3, 4, 5};
7 
8   auto [a, b, c, d, e] = arr;
9 
10   clang_analyzer_eval(a == 1); // expected-warning{{TRUE}}
11   clang_analyzer_eval(b == 2); // expected-warning{{TRUE}}
12   clang_analyzer_eval(c == 3); // expected-warning{{TRUE}}
13   clang_analyzer_eval(d == 4); // expected-warning{{TRUE}}
14   clang_analyzer_eval(e == 5); // expected-warning{{TRUE}}
15 }
16 
17 void array_uninit() {
18   int arr[5];
19 
20   auto [a, b, c, d, e] = arr;
21 
22   int x = e; // expected-warning{{Assigned value is garbage or undefined}}
23 }
24 
25 void lambda_init() {
26   int arr[] = {1, 2, 3, 4, 5};
27 
28   auto l = [arr] { return arr[0]; }();
29   clang_analyzer_eval(l == 1); // expected-warning{{TRUE}}
30 
31   l = [arr] { return arr[1]; }();
32   clang_analyzer_eval(l == 2); // expected-warning{{TRUE}}
33 
34   l = [arr] { return arr[2]; }();
35   clang_analyzer_eval(l == 3); // expected-warning{{TRUE}}
36 
37   l = [arr] { return arr[3]; }();
38   clang_analyzer_eval(l == 4); // expected-warning{{TRUE}}
39 
40   l = [arr] { return arr[4]; }();
41   clang_analyzer_eval(l == 5); // expected-warning{{TRUE}}
42 }
43 
44 void lambda_uninit() {
45   int arr[5];
46 
47   // FIXME: These should be Undefined, but we fail to read Undefined from a lazyCompoundVal
48   int l = [arr] { return arr[0]; }();
49   clang_analyzer_eval(l); // expected-warning{{UNKNOWN}}
50 
51   l = [arr] { return arr[1]; }();
52   clang_analyzer_eval(l); // expected-warning{{UNKNOWN}}
53 
54   l = [arr] { return arr[2]; }();
55   clang_analyzer_eval(l); // expected-warning{{UNKNOWN}}
56 
57   l = [arr] { return arr[3]; }();
58   clang_analyzer_eval(l); // expected-warning{{UNKNOWN}}
59 
60   l = [arr] { return arr[4]; }();
61   clang_analyzer_eval(l); // expected-warning{{UNKNOWN}}
62 }
63 
64 struct S {
65   int arr[5];
66 };
67 
68 void copy_ctor_init() {
69   S orig;
70   orig.arr[0] = 1;
71   orig.arr[1] = 2;
72   orig.arr[2] = 3;
73   orig.arr[3] = 4;
74   orig.arr[4] = 5;
75 
76   S copy = orig;
77   clang_analyzer_eval(copy.arr[0] == 1); // expected-warning{{TRUE}}
78   clang_analyzer_eval(copy.arr[1] == 2); // expected-warning{{TRUE}}
79   clang_analyzer_eval(copy.arr[2] == 3); // expected-warning{{TRUE}}
80   clang_analyzer_eval(copy.arr[3] == 4); // expected-warning{{TRUE}}
81   clang_analyzer_eval(copy.arr[4] == 5); // expected-warning{{TRUE}}
82 }
83 
84 void copy_ctor_uninit() {
85   S orig;
86 
87   S copy = orig;
88 
89   // FIXME: These should be Undefined, but we fail to read Undefined from a lazyCompoundVal.
90   // If the struct is not considered a small struct, instead of a copy, we store a lazy compound value.
91   // As the struct has an array data member, it is not considered small.
92   clang_analyzer_eval(copy.arr[0]); // expected-warning{{UNKNOWN}}
93   clang_analyzer_eval(copy.arr[1]); // expected-warning{{UNKNOWN}}
94   clang_analyzer_eval(copy.arr[2]); // expected-warning{{UNKNOWN}}
95   clang_analyzer_eval(copy.arr[3]); // expected-warning{{UNKNOWN}}
96   clang_analyzer_eval(copy.arr[4]); // expected-warning{{UNKNOWN}}
97 }
98 
99 void move_ctor_init() {
100   S orig;
101   orig.arr[0] = 1;
102   orig.arr[1] = 2;
103   orig.arr[2] = 3;
104   orig.arr[3] = 4;
105   orig.arr[4] = 5;
106 
107   S moved = (S &&) orig;
108 
109   clang_analyzer_eval(moved.arr[0] == 1); // expected-warning{{TRUE}}
110   clang_analyzer_eval(moved.arr[1] == 2); // expected-warning{{TRUE}}
111   clang_analyzer_eval(moved.arr[2] == 3); // expected-warning{{TRUE}}
112   clang_analyzer_eval(moved.arr[3] == 4); // expected-warning{{TRUE}}
113   clang_analyzer_eval(moved.arr[4] == 5); // expected-warning{{TRUE}}
114 }
115 
116 void move_ctor_uninit() {
117   S orig;
118 
119   S moved = (S &&) orig;
120 
121   // FIXME: These should be Undefined, but we fail to read Undefined from a lazyCompoundVal.
122   clang_analyzer_eval(moved.arr[0]); // expected-warning{{UNKNOWN}}
123   clang_analyzer_eval(moved.arr[1]); // expected-warning{{UNKNOWN}}
124   clang_analyzer_eval(moved.arr[2]); // expected-warning{{UNKNOWN}}
125   clang_analyzer_eval(moved.arr[3]); // expected-warning{{UNKNOWN}}
126   clang_analyzer_eval(moved.arr[4]); // expected-warning{{UNKNOWN}}
127 }
128 
129 // The struct has a user defined copy and move ctor, which allow us to
130 // track the values more precisely when an array of this struct is being
131 // copy/move initialized by ArrayInitLoopExpr.
132 struct S2 {
133   inline static int c = 0;
134   int i;
135 
136   S2() : i(++c) {}
137 
138   S2(const S2 &copy) {
139     i = copy.i + 1;
140   }
141 
142   S2(S2 &&move) {
143     i = move.i + 2;
144   }
145 };
146 
147 void array_init_non_pod() {
148   S2::c = 0;
149   S2 arr[4];
150 
151   auto [a, b, c, d] = arr;
152 
153   clang_analyzer_eval(a.i == 2); // expected-warning{{TRUE}}
154   clang_analyzer_eval(b.i == 3); // expected-warning{{TRUE}}
155   clang_analyzer_eval(c.i == 4); // expected-warning{{TRUE}}
156   clang_analyzer_eval(d.i == 5); // expected-warning{{TRUE}}
157 }
158 
159 struct S3 {
160   int i;
161 };
162 
163 // The duplicate is required to emit a warning at 2 different places.
164 struct S3_duplicate {
165   int i;
166 };
167 
168 void array_uninit_non_pod() {
169   S3 arr[1];
170 
171   auto [a] = arr; // expected-warning@159{{ in implicit constructor is garbage or undefined }}
172 }
173 
174 void lambda_init_non_pod() {
175   S2::c = 0;
176   S2 arr[4];
177 
178   auto l = [arr] { return arr[0].i; }();
179   clang_analyzer_eval(l == 2); // expected-warning{{TRUE}}
180 
181   l = [arr] { return arr[1].i; }();
182   clang_analyzer_eval(l == 3); // expected-warning{{TRUE}}
183 
184   l = [arr] { return arr[2].i; }();
185   clang_analyzer_eval(l == 4); // expected-warning{{TRUE}}
186 
187   l = [arr] { return arr[3].i; }();
188   clang_analyzer_eval(l == 5); // expected-warning{{TRUE}}
189 }
190 
191 void lambda_uninit_non_pod() {
192   S3_duplicate arr[4];
193 
194   int l = [arr] { return arr[3].i; }(); // expected-warning@164{{ in implicit constructor is garbage or undefined }}
195 }
196 
197 // If this struct is being copy/move constructed by the implicit ctors, ArrayInitLoopExpr
198 // is responsible for the initialization of 'arr' by copy/move constructing each of the
199 // elements.
200 struct S5 {
201   S2 arr[4];
202 };
203 
204 void copy_ctor_init_non_pod() {
205   S2::c = 0;
206   S5 orig;
207 
208   S5 copy = orig;
209   clang_analyzer_eval(copy.arr[0].i == 2); // expected-warning{{TRUE}}
210   clang_analyzer_eval(copy.arr[1].i == 3); // expected-warning{{TRUE}}
211   clang_analyzer_eval(copy.arr[2].i == 4); // expected-warning{{TRUE}}
212   clang_analyzer_eval(copy.arr[3].i == 5); // expected-warning{{TRUE}}
213 }
214 
215 void move_ctor_init_non_pod() {
216   S2::c = 0;
217   S5 orig;
218 
219   S5 moved = (S5 &&) orig;
220 
221   clang_analyzer_eval(moved.arr[0].i == 3); // expected-warning{{TRUE}}
222   clang_analyzer_eval(moved.arr[1].i == 4); // expected-warning{{TRUE}}
223   clang_analyzer_eval(moved.arr[2].i == 5); // expected-warning{{TRUE}}
224   clang_analyzer_eval(moved.arr[3].i == 6); // expected-warning{{TRUE}}
225 }
226 
227 //Note: This is the only solution I could find to check the values without
228 // crashing clang. For more details on the crash see Issue #57135.
229 void lambda_capture_multi_array() {
230   S3 arr[2][2] = {1,2,3,4};
231 
232   {
233     int x = [arr] { return arr[0][0].i; }();
234     clang_analyzer_eval(x == 1); // expected-warning{{TRUE}}
235   }
236 
237   {
238     int x = [arr] { return arr[0][1].i; }();
239     clang_analyzer_eval(x == 2); // expected-warning{{TRUE}}
240   }
241 
242   {
243     int x = [arr] { return arr[1][0].i; }();
244     clang_analyzer_eval(x == 3); // expected-warning{{TRUE}}
245   }
246 
247   {
248     int x = [arr] { return arr[1][1].i; }();
249     clang_analyzer_eval(x == 4); // expected-warning{{TRUE}}
250   }
251 }
252 
253 // This struct will force constructor inlining in MultiWrapper.
254 struct UserDefinedCtor {
255   int i;
256   UserDefinedCtor() {}
257   UserDefinedCtor(const UserDefinedCtor &copy) {
258     int j = 1;
259     i = copy.i;
260   }
261 };
262 
263 struct MultiWrapper {
264   UserDefinedCtor arr[2][2];
265 };
266 
267 void copy_ctor_multi() {
268   MultiWrapper MW;
269 
270   MW.arr[0][0].i = 0;
271   MW.arr[0][1].i = 1;
272   MW.arr[1][0].i = 2;
273   MW.arr[1][1].i = 3;
274 
275   MultiWrapper MWCopy = MW;
276 
277   clang_analyzer_eval(MWCopy.arr[0][0].i == 0); // expected-warning{{TRUE}}
278   clang_analyzer_eval(MWCopy.arr[0][1].i == 1); // expected-warning{{TRUE}}
279   clang_analyzer_eval(MWCopy.arr[1][0].i == 2); // expected-warning{{TRUE}}
280   clang_analyzer_eval(MWCopy.arr[1][1].i == 3); // expected-warning{{TRUE}}
281 }
282 
283 void move_ctor_multi() {
284   MultiWrapper MW;
285 
286   MW.arr[0][0].i = 0;
287   MW.arr[0][1].i = 1;
288   MW.arr[1][0].i = 2;
289   MW.arr[1][1].i = 3;
290 
291   MultiWrapper MWMove = (MultiWrapper &&) MW;
292 
293   clang_analyzer_eval(MWMove.arr[0][0].i == 0); // expected-warning{{TRUE}}
294   clang_analyzer_eval(MWMove.arr[0][1].i == 1); // expected-warning{{TRUE}}
295   clang_analyzer_eval(MWMove.arr[1][0].i == 2); // expected-warning{{TRUE}}
296   clang_analyzer_eval(MWMove.arr[1][1].i == 3); // expected-warning{{TRUE}}
297 }
298 
299 void structured_binding_multi() {
300   S3 arr[2][2] = {1,2,3,4};
301 
302   auto [a,b] = arr;
303 
304   clang_analyzer_eval(a[0].i == 1); // expected-warning{{TRUE}}
305   clang_analyzer_eval(a[1].i == 2); // expected-warning{{TRUE}}
306   clang_analyzer_eval(b[0].i == 3); // expected-warning{{TRUE}}
307   clang_analyzer_eval(b[1].i == 4); // expected-warning{{TRUE}}
308 }
309 
310 // This snippet used to crash
311 namespace crash {
312 
313 struct S
314 {
315   int x;
316   S() { x = 1; }
317 };
318 
319 void no_crash() {
320   S arr[0];
321   int n = 1;
322 
323   auto l = [arr, n] { return n; };
324 
325   int x = l();
326   clang_analyzer_eval(x == 1); // expected-warning{{TRUE}}
327 
328   // FIXME: This should be 'Undefined'.
329   clang_analyzer_eval(arr[0].x); // expected-warning{{UNKNOWN}}
330 }
331 
332 } // namespace crash
333 
334 namespace array_subscript_initializer {
335 struct S {
336   int x;
337 };
338 
339 void no_crash() {
340   S arr[][2] = {{1, 2}};
341 
342   const auto [a, b] = arr[0]; // no-crash
343 
344   clang_analyzer_eval(a.x == 1); // expected-warning{{TRUE}}
345   clang_analyzer_eval(b.x == 2); // expected-warning{{TRUE}}
346 }
347 } // namespace array_subscript_initializer
348 
349 namespace iterator_initializer {
350 struct S {
351   int x;
352 };
353 
354 void no_crash() {
355   S arr[][2] = {{1, 2}, {3, 4}};
356 
357   int i = 0;
358   for (const auto [a, b] : arr) { // no-crash
359     if (i == 0) {
360       clang_analyzer_eval(a.x == 1); // expected-warning{{TRUE}}
361       clang_analyzer_eval(b.x == 2); // expected-warning{{TRUE}}
362     } else {
363       clang_analyzer_eval(a.x == 3); // expected-warning{{TRUE}}
364       clang_analyzer_eval(b.x == 4); // expected-warning{{TRUE}}
365     }
366 
367     ++i;
368   }
369 }
370 } // namespace iterator_initializer
371