1 /* PR middle-end/91647 - missing -Warray-bounds accessing a zero-length array
2 of a declared object
3 { dg-do "compile" }
4 { dg-options "-O2 -Wall" }
5 { dg-require-effective-target alloca } */
6
7 /* pr102706: disabled warnings because the now-disabled conditions for the
8 bogus warnings to come up do not take cost analysis into account, and often
9 come up wrong. */
10 /* { dg-additional-options "-Wno-stringop-overflow" } */
11
12 typedef __INT16_TYPE__ int16_t;
13 typedef __INT32_TYPE__ int32_t;
14
15 void sink (void*);
16
17 /* Exercise a true flexible member. */
18
19 struct AX
20 {
21 int32_t n;
22 int16_t ax[]; // { dg-message "while referencing 'ax'" "member" }
23 };
24
25 static void warn_ax_local (struct AX *p)
26 {
27 p->ax[0] = 0; // { dg-warning "\\\[-Warray-bounds" }
28 p->ax[1] = 1; // { dg-warning "\\\[-Warray-bounds" }
29 }
30
31 static void nowarn_ax_extern (struct AX *p)
32 {
33 p->ax[0] = 0; p->ax[99] = 99; p->ax[999] = 999; p->ax[9999] = 9999;
34 }
35
36 static void warn_ax_local_buf (struct AX *p)
37 {
38 p->ax[0] = 4; p->ax[1] = 5; // { dg-bogus "\\\[-Wstringop-overflow" "pr102706" }
39 // { xfail { vect_slp_v2hi_store_align && { ! vect_slp_v4hi_store_unalign } } }
40
41 p->ax[2] = 6; // { dg-warning "\\\[-Warray-bounds" }
42 p->ax[3] = 7; // { dg-warning "\\\[-Warray-bounds" }
43 p->ax[4] = 8; // { dg-warning "\\\[-Warray-bounds" }
44 }
45
46 static void warn_ax_extern_buf (struct AX *p)
47 {
48 p->ax[0] = 9; p->ax[1] = 10; p->ax[2] = 11;
49
50 p->ax[3] = 12; // { dg-warning "\\\[-Warray-bounds" }
51 p->ax[4] = 13; // { dg-warning "\\\[-Warray-bounds" }
52 p->ax[5] = 14; // { dg-warning "\\\[-Warray-bounds" }
53 }
54
55 static void nowarn_ax_extern_bufx (struct AX *p)
56 {
57 p->ax[0] = 0; p->ax[99] = 99; p->ax[999] = 999; p->ax[9999] = 9999;
58 }
59
60 static void nowarn_ax_ref (struct AX *p)
61 {
62 p->ax[0] = 0; p->ax[99] = 99; p->ax[999] = 999; p->ax[9999] = 9999;
63 }
64
65 void test_ax (struct AX *p, unsigned n)
66 {
67 {
68 struct AX sax; // { dg-message "defined here" "struct definition" }
69 warn_ax_local (&sax);
70 sink (&sax);
71 }
72
73 {
74 extern
75 struct AX xsax;
76 nowarn_ax_extern (&xsax);
77 sink (&xsax);
78 }
79
80 {
81 /* Verify out-of-bounds access to the local BUF is diagnosed. */
82 char ax_buf_p2[sizeof (struct AX) + 2 * sizeof (int16_t)];
83 warn_ax_local_buf ((struct AX*) ax_buf_p2);
84 sink (ax_buf_p2);
85 }
86
87 {
88 /* Verify out-of-bounds access to the extern BUF with a known
89 bound is diagnosed. */
90 extern char ax_buf_p3[sizeof (struct AX) + 3 * sizeof (int16_t)];
91 warn_ax_extern_buf ((struct AX*) ax_buf_p3);
92 sink (ax_buf_p3);
93 }
94
95 {
96 /* Verify that accesses to BUFX with an unknown bound are not
97 diagnosed. */
98 extern char bufx[];
99 nowarn_ax_extern_bufx ((struct AX*) bufx);
100 sink (bufx);
101 }
102
103 {
104 /* Verify that accesses to BUFN with a runtime bound are not
105 diagnosed. */
106 char bufn[n];
107 nowarn_ax_extern_bufx ((struct AX*) bufn);
108 sink (bufn);
109 }
110
111 nowarn_ax_ref (p);
112 }
113
114
115 /* Exercise a zero-length trailing member array. It's the same as above
116 except that extern declarations with no definitions are considered to
117 have zero elements (they can't be initialized to have any). */
118
119 struct A0
120 {
121 int32_t n;
122 int16_t a0[0]; // { dg-message "while referencing 'a0'" "member" }
123 };
124
125 static void warn_a0_local (struct A0 *p)
126 {
127 p->a0[0] = 0; // { dg-warning "\\\[-Warray-bounds" }
128 p->a0[1] = 1; // { dg-warning "\\\[-Warray-bounds" }
129 }
130
131 static void warn_a0_extern (struct A0 *p)
132 {
133 p->a0[0] = 2; // { dg-warning "\\\[-Warray-bounds" }
134 p->a0[1] = 3; // { dg-warning "\\\[-Warray-bounds" }
135 }
136
137 static void warn_a0_local_buf (struct A0 *p)
138 {
139 p->a0[0] = 4; p->a0[1] = 5; // { dg-bogus "\\\[-Wstringop-overflow" "pr102706" }
140 // { xfail { vect_slp_v2hi_store_align && { ! vect_slp_v4hi_store_unalign } } }
141
142 p->a0[2] = 6; // { dg-warning "\\\[-Warray-bounds" }
143 p->a0[3] = 7; // { dg-warning "\\\[-Warray-bounds" }
144 p->a0[4] = 8; // { dg-warning "\\\[-Warray-bounds" }
145 }
146
147 static void warn_a0_extern_buf (struct A0 *p)
148 {
149 p->a0[0] = 9; p->a0[1] = 10; p->a0[2] = 11;
150
151 p->a0[3] = 12; // { dg-warning "\\\[-Warray-bounds" }
152 p->a0[4] = 13; // { dg-warning "\\\[-Warray-bounds" }
153 p->a0[5] = 14; // { dg-warning "\\\[-Warray-bounds" }
154 }
155
156 static void nowarn_a0_extern_bufx (struct A0 *p)
157 {
158 p->a0[0] = 0; p->a0[99] = 99; p->a0[999] = 999; p->a0[9999] = 9999;
159 }
160
161 static void nowarn_a0_ref (struct A0 *p)
162 {
163 p->a0[0] = 0; p->a0[99] = 99; p->a0[999] = 999; p->a0[9999] = 9999;
164 }
165
166 void test_a0 (struct A0 *p, unsigned n)
167 {
168 {
169 struct A0 sa0; // { dg-message "defined here" "struct definition" }
170 warn_a0_local (&sa0);
171 sink (&sa0);
172 }
173
174 {
175 extern
176 struct A0 xsa0; // { dg-message "defined here" "struct definition" }
177 warn_a0_extern (&xsa0);
178 sink (&xsa0);
179 }
180
181 {
182 /* Verify out-of-bounds access to the local BUF is diagnosed. */
183 char a0_buf_p2[sizeof (struct A0) + 2 * sizeof (int16_t)];
184 warn_a0_local_buf ((struct A0*) a0_buf_p2);
185 sink (a0_buf_p2);
186 }
187
188 {
189 /* Verify out-of-bounds access to the extern BUF with a known
190 bound is diagnosed. */
191 extern char a0_buf_p3[sizeof (struct A0) + 3 * sizeof (int16_t)];
192 warn_a0_extern_buf ((struct A0*) a0_buf_p3);
193 sink (a0_buf_p3);
194 }
195
196 {
197 /* Verify that accesses to BUFX with an unknown bound are not
198 diagnosed. */
199 extern char bufx[];
200 nowarn_a0_extern_bufx ((struct A0*) bufx);
201 sink (bufx);
202 }
203
204 {
205 /* Verify that accesses to BUFN with a runtime bound are not
206 diagnosed. */
207 char bufn[n];
208 nowarn_a0_extern_bufx ((struct A0*) bufn);
209 sink (bufn);
210 }
211
212 nowarn_a0_ref (p);
213 }
214
215
216 /* Exercise a one-element trailing member array. It's the same as above
217 except that it has exactly one element. */
218
219 struct A1
220 {
221 int32_t n;
222 __attribute__ ((aligned (4)))
223 int16_t a1[1]; // { dg-message "while referencing 'a1'" }
224 };
225
226 static void warn_a1_local_noinit (struct A1 *p)
227 {
228 p->a1[0] = 0;
229 p->a1[1] = 1; // { dg-warning "\\\[-Warray-bounds" }
230 p->a1[2] = 2; // { dg-warning "\\\[-Warray-bounds" }
231 }
232
233 static void warn_a1_extern (struct A1 *p)
234 {
235 p->a1[0] = 0;
236 p->a1[1] = 1; // { dg-warning "\\\[-Warray-bounds" }
237 p->a1[2] = 2; // { dg-warning "\\\[-Warray-bounds" }
238 }
239
240 static void warn_a1_init (struct A1 *p)
241 {
242 p->a1[0] = 0;
243 p->a1[1] = 1; // { dg-warning "\\\[-Warray-bounds" }
244 p->a1[2] = 2; // { dg-warning "\\\[-Warray-bounds" }
245 }
246
247 static void warn_a1_local_buf (struct A1 *p)
248 {
249 p->a1[0] = 0; p->a1[1] = 1; p->a1[2] = 2; p->a1[3] = 3;
250
251 p->a1[4] = 4; // { dg-warning "\\\[-Warray-bounds" }
252 }
253
254 static void warn_a1_extern_buf (struct A1 *p)
255 {
256 p->a1[0] = 0; p->a1[1] = 1; p->a1[2] = 2; p->a1[3] = 3; p->a1[4] = 4;
257
258 p->a1[5] = 5; // { dg-warning "\\\[-Warray-bounds" }
259 }
260
261 static void nowarn_a1_extern_bufx (struct A1 *p)
262 {
263 p->a1[0] = 0; p->a1[99] = 99; p->a1[999] = 999; p->a1[9999] = 9999;
264 }
265
266 static void nowarn_a1_ref (struct A1 *p)
267 {
268 p->a1[0] = 0; p->a1[99] = 99; p->a1[999] = 999; p->a1[9999] = 9999;
269 }
270
271 void test_a1 (struct A1 *p, unsigned n)
272 {
273 {
274 struct A1 a1;
275 warn_a1_local_noinit (&a1);
276 sink (&a1);
277 }
278
279 {
280 extern struct A1 a1x;
281 warn_a1_extern (&a1x);
282 sink (&a1x);
283 }
284 {
285 struct A1 a1 = { 0, { 1 } };
286 warn_a1_init (&a1);
287 sink (&a1);
288 }
289
290 {
291 /* Verify out-of-bounds access to the local BUF is diagnosed. */
292 char buf_p2[sizeof (struct A1) + 2 * sizeof (int16_t)];
293 warn_a1_local_buf ((struct A1*) buf_p2);
294 sink (buf_p2);
295 }
296
297 {
298 /* Verify out-of-bounds access to the extern BUF with a known
299 bound is diagnosed. */
300 extern char a1_buf_p3[sizeof (struct A1) + 3 * sizeof (int16_t)];
301 warn_a1_extern_buf ((struct A1*) a1_buf_p3);
302 sink (a1_buf_p3);
303 }
304
305 {
306 /* Verify that accesses to BUFX with an unknown bound are not
307 diagnosed. */
308 extern char bufx[];
309 nowarn_a1_extern_bufx ((struct A1*) bufx);
310 sink (bufx);
311 }
312
313 {
314 /* Verify that accesses to BUFN with a runtime bound are not
315 diagnosed. */
316 char bufn[n];
317 nowarn_a1_extern_bufx ((struct A1*) bufn);
318 sink (bufn);
319 }
320
321 nowarn_a1_ref (p);
322 }
323
324
325 /* Exercise a two-element trailing member array. It's treated
326 the same as an interior array member. */
327
328 struct A2
329 {
330 int32_t n;
331 int16_t a2[2]; // { dg-message "while referencing 'a2'" }
332 };
333
334 static void warn_a2_noinit (struct A2 *p)
335 {
336 p->a2[0] = 0; p->a2[1] = 1;
337
338 p->a2[2] = 2; // { dg-warning "\\\[-Warray-bounds" }
339 }
340
341 static void warn_a2_init (struct A2 *p)
342 {
343 p->a2[0] = 0; p->a2[1] = 1;
344
345 p->a2[2] = 2; // { dg-warning "\\\[-Warray-bounds" }
346 p->a2[9] = 9; // { dg-warning "\\\[-Warray-bounds" }
347 }
348
349 static void warn_a2_ref (struct A2 *p)
350 {
351 p->a2[0] = 0; p->a2[1] = 1;
352
353 p->a2[2] = 2; // { dg-warning "\\\[-Warray-bounds" }
354 p->a2[9] = 9; // { dg-warning "\\\[-Warray-bounds" }
355 }
356
357 void test_a2 (struct A2 *p)
358 {
359 {
360 struct A2 a2;
361 warn_a2_noinit (&a2);
362 sink (&a2);
363 }
364
365 {
366 struct A2 a2 = { 0, { 1, 2 } };
367 warn_a2_init (&a2);
368 sink (&a2);
369 }
370
371 warn_a2_ref (p);
372 }