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