1 /* PR tree-optimization/83671 - fix for false positive reported by
2 -Wstringop-overflow does not work with inlining
3 { dg-do compile }
4 { dg-options "-O1 -fdump-tree-optimized" } */
5
6 #include "strlenopt.h"
7
8 #define DIFF_MAX __PTRDIFF_MAX__
9
10 #define CAT(x, y) x ## y
11 #define CONCAT(x, y) CAT (x, y)
12 #define FAILNAME(name) CONCAT (call_ ## name ##_on_line_, __LINE__)
13
14 #define FAIL(name) do { \
15 extern void FAILNAME (name) (void); \
16 FAILNAME (name)(); \
17 } while (0)
18
19 /* Macros to emit a call to funcation named
20 call_in_{true,false}_branch_not_eliminated_on_line_NNN()
21 for each call that's expected to be eliminated. The dg-final
22 scan-tree-dump-time directive at the bottom of the test verifies
23 that no such call appears in output. */
24 #define ELIM_TRUE(expr) \
25 if (!(expr)) FAIL (in_true_branch_not_eliminated); else (void)0
26
27 #define ELIM_FALSE(expr) \
28 if (!!(expr)) FAIL (in_false_branch_not_eliminated); else (void)0
29
30 /* Macro to emit a call to a function named
31 call_made_in_{true,false}_branch_on_line_NNN()
32 for each call that's expected to be retained. The dg-final
33 scan-tree-dump-time directive at the bottom of the test verifies
34 that the expected number of both kinds of calls appears in output
35 (a pair for each line with the invocation of the KEEP() macro. */
36 #define KEEP(expr) \
37 if (expr) \
38 FAIL (made_in_true_branch); \
39 else \
40 FAIL (made_in_false_branch)
41
42 typedef char A3[3], A5[5], A7[7], AX[];
43
44 typedef A3 A7_3[7];
45 typedef A3 AX_3[];
46 typedef A5 A7_5[7];
47 typedef A7 A5_7[5];
48
49 extern A7_3 a7_3;
50 extern A5_7 a5_7;
51 extern AX_3 ax_3;
52
53 extern A3 a3;
54 extern A7 a5;
55 extern A7 a7;
56 extern AX ax;
57
58 extern A3 *pa3;
59 extern A5 *pa5;
60 extern A7 *pa7;
61
62 extern A7_3 *pa7_3;
63 extern AX_3 *pax_3;
64 extern A5_7 *pa5_7;
65 extern A7_5 *pa7_5;
66
67 extern char *ptr;
68
69 struct MemArrays0 {
70 A7_3 a7_3;
71 A5_7 a5_7;
72 char a3[3], a5[5], a0[0];
73 };
74 struct MemArraysX { char a3[3], a5[5], ax[]; };
75 struct MemArrays7 { char a3[3], a5[5], a7[7]; };
76
77 struct MemArrays0 ma0_3_5_7[3][5][7];
78
elim_strings(int i)79 void elim_strings (int i)
80 {
81 ELIM_TRUE (strlen (i < 0 ? "123" : "321") == 3);
82 ELIM_FALSE (strlen (i < 0 ? "123" : "321") > 3);
83 ELIM_FALSE (strlen (i < 0 ? "123" : "321") < 3);
84
85 ELIM_TRUE (strlen (i < 0 ? "123" : "4321") >= 3);
86 ELIM_FALSE (strlen (i < 0 ? "123" : "4321") > 4);
87 ELIM_FALSE (strlen (i < 0 ? "123" : "4321") < 3);
88
89 ELIM_TRUE (strlen (i < 0 ? "1234" : "321") >= 3);
90 ELIM_FALSE (strlen (i < 0 ? "1234" : "321") < 3);
91 ELIM_FALSE (strlen (i < 0 ? "1234" : "321") > 4);
92
93 ELIM_TRUE (strlen (i < 0 ? "123" : "4321") <= 4);
94 ELIM_TRUE (strlen (i < 0 ? "1234" : "321") <= 4);
95
96 ELIM_TRUE (strlen (i < 0 ? "1" : "123456789") <= 9);
97 ELIM_TRUE (strlen (i < 0 ? "1" : "123456789") >= 1);
98 }
99
100 /* Verify that strlen calls involving uninitialized global arrays
101 of known size are eliminated when they appear in expressions
102 that test for results that must be true. */
elim_global_arrays(int i)103 void elim_global_arrays (int i)
104 {
105 /* Verify that the expression involving the strlen call as well
106 as whatever depends on it is eliminated from the test output.
107 All these expressions must be trivially true. */
108 ELIM_TRUE (strlen (a7_3[0]) < sizeof a7_3);
109 ELIM_TRUE (strlen (a7_3[1]) < sizeof a7_3 - sizeof *a7_3);
110 ELIM_TRUE (strlen (a7_3[6]) < sizeof a7_3 - 5 * sizeof *a7_3);
111 ELIM_TRUE (strlen (a7_3[i]) < sizeof a7_3);
112
113 ELIM_TRUE (strlen (a5_7[0]) < sizeof a5_7);
114 ELIM_TRUE (strlen (a5_7[1]) < sizeof a5_7 - sizeof *a5_7);
115 ELIM_TRUE (strlen (a5_7[4]) < sizeof a5_7 - 3 * sizeof *a5_7);
116 ELIM_TRUE (strlen (a5_7[i]) < sizeof a5_7);
117
118 /* Even when treating a multi-dimensional array as a single string
119 the length must be less DIFF_MAX - (ax_3[i] - ax_3[0]) but GCC
120 doesn't do that computation yet so avoid testing it. */
121 ELIM_TRUE (strlen (ax_3[0]) < DIFF_MAX);
122 ELIM_TRUE (strlen (ax_3[1]) < DIFF_MAX);
123 ELIM_TRUE (strlen (ax_3[9]) < DIFF_MAX);
124 ELIM_TRUE (strlen (ax_3[i]) < DIFF_MAX);
125
126 ELIM_TRUE (strlen (a3) < sizeof a3);
127 ELIM_TRUE (strlen (a7) < sizeof a7);
128
129 ELIM_TRUE (strlen (ax) != DIFF_MAX);
130 /* ELIM_TRUE (strlen (ax) != DIFF_MAX - 1); */
131 /* ELIM_TRUE (strlen (ax) < DIFF_MAX - 1); */
132 }
133
elim_pointer_to_arrays(void)134 void elim_pointer_to_arrays (void)
135 {
136 /* Unfortunately, GCC cannot be trusted not to misuse a pointer
137 to a smaller array to point to an object of a bigger type so
138 the strlen range optimization must assume each array pointer
139 points effectively to an array of an unknown bound. */
140 ELIM_TRUE (strlen (*pa7) < DIFF_MAX);
141 ELIM_TRUE (strlen (*pa5) < DIFF_MAX);
142 ELIM_TRUE (strlen (*pa3) < DIFF_MAX);
143
144 ELIM_TRUE (strlen ((*pa7_3)[0]) < DIFF_MAX);
145 ELIM_TRUE (strlen ((*pa7_3)[1]) < DIFF_MAX);
146 ELIM_TRUE (strlen ((*pa7_3)[6]) < DIFF_MAX);
147
148 ELIM_TRUE (strlen ((*pax_3)[0]) < DIFF_MAX);
149 ELIM_TRUE (strlen ((*pax_3)[1]) < DIFF_MAX);
150 ELIM_TRUE (strlen ((*pax_3)[9]) < DIFF_MAX);
151
152 ELIM_TRUE (strlen ((*pa5_7)[0]) < DIFF_MAX);
153 ELIM_TRUE (strlen ((*pa5_7)[1]) < DIFF_MAX);
154 ELIM_TRUE (strlen ((*pa5_7)[4]) < DIFF_MAX);
155 }
156
elim_global_arrays_and_strings(int i)157 void elim_global_arrays_and_strings (int i)
158 {
159 ELIM_TRUE (strlen (i < 0 ? a3 : "") < 3);
160 ELIM_TRUE (strlen (i < 0 ? a3 : "1") < 3);
161 ELIM_TRUE (strlen (i < 0 ? a3 : "12") < 3);
162 ELIM_TRUE (strlen (i < 0 ? a3 : "123") < 4);
163
164 ELIM_FALSE (strlen (i < 0 ? a3 : "") > 3);
165 ELIM_FALSE (strlen (i < 0 ? a3 : "1") > 3);
166 ELIM_FALSE (strlen (i < 0 ? a3 : "12") > 3);
167 ELIM_FALSE (strlen (i < 0 ? a3 : "123") > 4);
168
169 ELIM_TRUE (strlen (i < 0 ? a7 : "") < 7);
170 ELIM_TRUE (strlen (i < 0 ? a7 : "1") < 7);
171 ELIM_TRUE (strlen (i < 0 ? a7 : "12") < 7);
172 ELIM_TRUE (strlen (i < 0 ? a7 : "123") < 7);
173 ELIM_TRUE (strlen (i < 0 ? a7 : "123456") < 7);
174 ELIM_TRUE (strlen (i < 0 ? a7 : "1234567") < 8);
175
176 ELIM_FALSE (strlen (i < 0 ? a7 : "") > 6);
177 ELIM_FALSE (strlen (i < 0 ? a7 : "1") > 6);
178 ELIM_FALSE (strlen (i < 0 ? a7 : "12") > 6);
179 ELIM_FALSE (strlen (i < 0 ? a7 : "123") > 6);
180 ELIM_FALSE (strlen (i < 0 ? a7 : "123456") > 7);
181 ELIM_FALSE (strlen (i < 0 ? a7 : "1234567") > 8);
182 }
183
elim_member_arrays_obj(int i)184 void elim_member_arrays_obj (int i)
185 {
186 ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a3) < sizeof ma0_3_5_7);
187 ELIM_TRUE (strlen (ma0_3_5_7[0][0][1].a3) < sizeof ma0_3_5_7);
188 ELIM_TRUE (strlen (ma0_3_5_7[0][0][2].a3) < sizeof ma0_3_5_7);
189 ELIM_TRUE (strlen (ma0_3_5_7[0][0][6].a3) < sizeof ma0_3_5_7);
190
191 ELIM_TRUE (strlen (ma0_3_5_7[1][0][0].a3) < sizeof ma0_3_5_7);
192 ELIM_TRUE (strlen (ma0_3_5_7[2][0][1].a3) < sizeof ma0_3_5_7);
193
194 ELIM_TRUE (strlen (ma0_3_5_7[1][1][0].a3) < sizeof ma0_3_5_7);
195 ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a3) < sizeof ma0_3_5_7);
196
197 ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a5) < sizeof ma0_3_5_7);
198 ELIM_TRUE (strlen (ma0_3_5_7[0][0][1].a5) < sizeof ma0_3_5_7);
199 ELIM_TRUE (strlen (ma0_3_5_7[0][0][2].a5) < sizeof ma0_3_5_7);
200 ELIM_TRUE (strlen (ma0_3_5_7[0][0][6].a5) < sizeof ma0_3_5_7);
201
202 ELIM_TRUE (strlen (ma0_3_5_7[1][0][0].a5) < sizeof ma0_3_5_7);
203 ELIM_TRUE (strlen (ma0_3_5_7[2][0][1].a5) < sizeof ma0_3_5_7);
204
205 ELIM_TRUE (strlen (ma0_3_5_7[1][1][0].a5) < sizeof ma0_3_5_7);
206 ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5) < sizeof ma0_3_5_7);
207
208 ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a7_3[0]) < sizeof ma0_3_5_7);
209 ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a7_3[2]) < sizeof ma0_3_5_7);
210
211 ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a5_7[0]) < sizeof ma0_3_5_7);
212 ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5_7[4]) < sizeof ma0_3_5_7);
213 }
214
215
216 #line 1000
217
218 /* Verify that strlen calls involving uninitialized global arrays
219 of unknown size are not eliminated when they appear in expressions
220 that test for results that need not be true. */
keep_global_arrays(int i)221 void keep_global_arrays (int i)
222 {
223 KEEP (strlen (a7_3[0]) < 2);
224 KEEP (strlen (a7_3[1]) < 2);
225 KEEP (strlen (a7_3[6]) < 2);
226 KEEP (strlen (a7_3[i]) < 2);
227
228 KEEP (strlen (a5_7[0]) < 6);
229 KEEP (strlen (a5_7[1]) < 6);
230 KEEP (strlen (a5_7[4]) < 6);
231 KEEP (strlen (a5_7[i]) < 6);
232
233 /* Verify also that tests (and strlen calls) are not eliminated
234 for results greater than what would the size of the innermost
235 array suggest might be possible (in case the element array is
236 not nul-terminated), even though such calls are undefined. */
237 KEEP (strlen (a5_7[0]) > sizeof a5_7 - 2);
238 KEEP (strlen (a5_7[1]) > sizeof a5_7 - sizeof a5_7[1] - 2);
239 KEEP (strlen (a5_7[i]) > sizeof a5_7 - 2);
240
241 KEEP (strlen (ax_3[0]) < 2);
242 KEEP (strlen (ax_3[1]) < 2);
243 KEEP (strlen (ax_3[2]) < 2);
244 KEEP (strlen (ax_3[i]) < 2);
245
246 /* Here again, verify that the ax_3 matrix is treated essentially
247 as a flat array of unknown bound for the benefit of all the
248 undefined code out there that might rely on it. */
249 KEEP (strlen (ax_3[0]) > 3);
250 KEEP (strlen (ax_3[1]) > 9);
251 KEEP (strlen (ax_3[2]) > 99);
252 KEEP (strlen (ax_3[i]) > 999);
253
254 KEEP (strlen (a3) < 2);
255 KEEP (strlen (a7) < 6);
256
257 KEEP (strlen (a3 + i) < 2);
258 KEEP (strlen (a7 + i) < 2);
259
260 /* The length of an array of unknown size may be as large as
261 DIFF_MAX - 2. */
262 KEEP (strlen (ax) != DIFF_MAX - 2);
263 KEEP (strlen (ax) < DIFF_MAX - 2);
264 KEEP (strlen (ax) < 999);
265 KEEP (strlen (ax) < 1);
266 }
267
keep_pointer_to_arrays(int i)268 void keep_pointer_to_arrays (int i)
269 {
270 KEEP (strlen (*pa7) < 6);
271 KEEP (strlen (*pa5) < 4);
272 KEEP (strlen (*pa3) < 2);
273
274 /* Since GCC cannot be trusted not to misuse a pointer to a smaller
275 array to point to an object of a larger type verify that the bound
276 in a pointer to an array of a known bound isn't relied on for
277 the strlen range optimization. If GCC is fixed to avoid these
278 misuses these tests can be removed. */
279 KEEP (strlen (*pa7) > sizeof *pa7);
280 KEEP (strlen (*pa5) > sizeof *pa5);
281 KEEP (strlen (*pa3) > sizeof *pa3);
282
283 KEEP (strlen ((*pa7_3)[0]) < 2);
284 KEEP (strlen ((*pa7_3)[1]) < 2);
285 KEEP (strlen ((*pa7_3)[6]) < 2);
286 KEEP (strlen ((*pa7_3)[i]) < 2);
287
288 /* Same as above. */
289 KEEP (strlen ((*pa7_3)[0]) > sizeof *pa7_3);
290 KEEP (strlen ((*pa7_3)[i]) > sizeof *pa7_3);
291
292 KEEP (strlen ((*pax_3)[0]) < 2);
293 KEEP (strlen ((*pax_3)[1]) < 2);
294 KEEP (strlen ((*pax_3)[9]) < 2);
295 KEEP (strlen ((*pax_3)[i]) < 2);
296
297 /* Same as above. */
298 KEEP (strlen ((*pax_3)[0]) > 3);
299 KEEP (strlen ((*pax_3)[i]) > 333);
300
301 KEEP (strlen ((*pa5_7)[0]) < 6);
302 KEEP (strlen ((*pa5_7)[1]) < 6);
303 KEEP (strlen ((*pa5_7)[4]) < 6);
304 KEEP (strlen ((*pa5_7)[i]) < 6);
305
306 /* Same as above. */
307 KEEP (strlen ((*pa5_7)[0]) > sizeof *pa5_7);
308 KEEP (strlen ((*pa5_7)[i]) > sizeof *pa5_7);
309 }
310
keep_global_arrays_and_strings(int i)311 void keep_global_arrays_and_strings (int i)
312 {
313 KEEP (strlen (i < 0 ? a3 : "") < 2);
314 KEEP (strlen (i < 0 ? a3 : "1") < 2);
315 KEEP (strlen (i < 0 ? a3 : "12") < 2);
316 KEEP (strlen (i < 0 ? a3 : "123") < 3);
317
318 KEEP (strlen (i < 0 ? a7 : "") < 5);
319 KEEP (strlen (i < 0 ? a7 : "1") < 5);
320 KEEP (strlen (i < 0 ? a7 : "12") < 5);
321 KEEP (strlen (i < 0 ? a7 : "123") < 5);
322 KEEP (strlen (i < 0 ? a7 : "123456") < 6);
323 KEEP (strlen (i < 0 ? a7 : "1234567") < 6);
324
325 /* Verify that a matrix is treated as a flat array even in a conditional
326 expression (i.e., don't assume that a7_3[0] is nul-terminated, even
327 though calling strlen() on such an array is undefined). */
328 KEEP (strlen (i < 0 ? a7_3[0] : "") > 7);
329 KEEP (strlen (i < 0 ? a7_3[i] : "") > 7);
330 }
331
keep_member_arrays_obj(int i)332 void keep_member_arrays_obj (int i)
333 {
334 KEEP (strlen (ma0_3_5_7[0][0][0].a3) < 2);
335 KEEP (strlen (ma0_3_5_7[0][0][1].a3) < 2);
336 KEEP (strlen (ma0_3_5_7[0][0][2].a3) < 2);
337 KEEP (strlen (ma0_3_5_7[0][0][6].a3) < 2);
338
339 KEEP (strlen (ma0_3_5_7[1][0][0].a3) < 2);
340 KEEP (strlen (ma0_3_5_7[2][0][1].a3) < 2);
341
342 KEEP (strlen (ma0_3_5_7[1][1][0].a3) < 2);
343 KEEP (strlen (ma0_3_5_7[2][4][6].a3) < 2);
344
345 KEEP (strlen (ma0_3_5_7[0][0][0].a5) < 4);
346 KEEP (strlen (ma0_3_5_7[0][0][1].a5) < 4);
347 KEEP (strlen (ma0_3_5_7[0][0][2].a5) < 4);
348 KEEP (strlen (ma0_3_5_7[0][0][6].a5) < 4);
349
350 KEEP (strlen (ma0_3_5_7[1][0][0].a5) < 4);
351 KEEP (strlen (ma0_3_5_7[2][0][1].a5) < 4);
352
353 KEEP (strlen (ma0_3_5_7[1][1][0].a5) < 4);
354 KEEP (strlen (ma0_3_5_7[2][4][6].a5) < 4);
355
356 KEEP (strlen (ma0_3_5_7[0][0][0].a7_3[0]) < 2);
357 KEEP (strlen (ma0_3_5_7[2][4][6].a7_3[2]) < 2);
358
359 KEEP (strlen (ma0_3_5_7[0][0][0].a5_7[0]) < 6);
360 KEEP (strlen (ma0_3_5_7[2][4][6].a5_7[4]) < 6);
361
362 /* Again, verify that the .a3 array isn't assumed to necessarily
363 be nul-terminated. */
364 KEEP (strlen (ma0_3_5_7[0][0][0].a3) > 2);
365 KEEP (strlen (ma0_3_5_7[0][0][6].a3) > 2);
366 KEEP (strlen (ma0_3_5_7[0][0][i].a3) > 2);
367 }
368
keep_member_arrays_ptr(struct MemArrays0 * ma0,struct MemArraysX * max,struct MemArrays7 * ma7,int i)369 void keep_member_arrays_ptr (struct MemArrays0 *ma0,
370 struct MemArraysX *max,
371 struct MemArrays7 *ma7,
372 int i)
373 {
374 KEEP (strlen (ma0->a7_3[0]) > 0);
375 KEEP (strlen (ma0->a7_3[0]) < 2);
376 KEEP (strlen (ma0->a7_3[1]) < 2);
377 KEEP (strlen (ma0->a7_3[6]) < 2);
378 KEEP (strlen (ma0->a7_3[6]) < 2);
379 KEEP (strlen (ma0->a7_3[i]) > 0);
380 KEEP (strlen (ma0->a7_3[i]) < 2);
381 KEEP (strlen (ma0->a7_3[i]) < 2);
382
383 /* Again, verify that the member array isn't assumed to necessarily
384 be nul-terminated. */
385 KEEP (strlen (ma0->a7_3[0]) > sizeof ma0->a7_3);
386 KEEP (strlen (ma0->a7_3[i]) > sizeof ma0->a7_3);
387
388 KEEP (strlen (ma0->a5_7[0]) < 5);
389 KEEP (strlen (ma0[0].a5_7[0]) < 5);
390 KEEP (strlen (ma0[1].a5_7[0]) < 5);
391 KEEP (strlen (ma0[9].a5_7[0]) < 5);
392 KEEP (strlen (ma0[9].a5_7[4]) < 5);
393 KEEP (strlen (ma0[i].a5_7[4]) < 5);
394 KEEP (strlen (ma0[i].a5_7[i]) < 5);
395
396 /* Same as above. */
397 KEEP (strlen (ma0[i].a5_7[i]) > sizeof ma0[i].a5_7);
398
399 KEEP (strlen (ma0->a0) < DIFF_MAX - 2);
400 KEEP (strlen (ma0->a0) < 999);
401 KEEP (strlen (ma0->a0) < 1);
402
403 KEEP (strlen (max->ax) < DIFF_MAX - 2);
404 KEEP (strlen (max->ax) < 999);
405 KEEP (strlen (max->ax) < 1);
406
407 KEEP (strlen (ma7->a7) < DIFF_MAX - 2);
408 KEEP (strlen (ma7->a7) < 999);
409 KEEP (strlen (ma7->a7) < 1);
410 }
411
keep_pointers(const char * s)412 void keep_pointers (const char *s)
413 {
414 KEEP (strlen (ptr) < DIFF_MAX - 2);
415 KEEP (strlen (ptr) < 999);
416 KEEP (strlen (ptr) < 1);
417
418 KEEP (strlen (s) < DIFF_MAX - 2);
419 KEEP (strlen (s) < 999);
420 KEEP (strlen (s) < 1);
421 }
422
423
424 /* { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated_" 0 "optimized" } }
425 { dg-final { scan-tree-dump-times "call_in_false_branch_not_eliminated_" 0 "optimized" } }
426
427 { dg-final { scan-tree-dump-times "call_made_in_true_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 119 "optimized" } }
428 { dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 119 "optimized" } } */
429