1 /* PR middle-end/91458 - inconsistent warning for writing past the end
2    of an array member
3    { dg-do compile }
4    { dg-options "-O2 -Wall -Wno-array-bounds" } */
5 
6 #define NOIPA __attribute__ ((noipa))
7 
8 void sink (void*);
9 
10 // Exercise flexible array members.
11 
12 struct Ax
13 {
14   char n;
15   char a[];                     // { dg-message "at offset \[0-2\] to object 'Ax::a' declared here" "note: flexarray" }
16 };
17 
18 // Verify warning for a definition with no initializer.
19 Ax ax_;
20 
gax_()21 NOIPA void gax_ ()
22 {
23   ax_.a[0] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
24   ax_.a[1] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
25   ax_.a[2] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
26 }
27 
28 // Verify warning for access to a definition with an initializer that doesn't
29 // initialize the flexible array member.
30 Ax ax0 = { 0 };
31 
gax0()32 NOIPA void gax0 ()
33 {
34   ax0.a[0] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
35   ax0.a[1] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
36   ax0.a[2] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
37 }
38 
39 // Verify warning for access to a definition with an initializer that
40 // initializes the flexible array member to empty.
41 Ax ax0_ = { 0, { } };
42 
gax0_()43 NOIPA void gax0_ ()
44 {
45   ax0_.a[0] = 0;                // { dg-warning "\\\[-Wstringop-overflow" }
46   ax0_.a[1] = 0;                // { dg-warning "\\\[-Wstringop-overflow" }
47   ax0_.a[2] = 0;                // { dg-warning "\\\[-Wstringop-overflow" }
48 }
49 
50 // Verify warning for out-of-bounds accesses to a definition with
51 // an initializer.
52 Ax ax1 = { 1, { 0 } };
53 
gax1()54 NOIPA void gax1 ()
55 {
56   ax1.a[0] = 0;
57   ax1.a[1] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
58   ax1.a[2] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
59 }
60 
61 Ax ax2 = { 2, { 1, 0 } };
62 
gax2()63 NOIPA void gax2 ()
64 {
65   ax2.a[0] = 0;
66   ax2.a[1] = 0;
67   ax2.a[2] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
68 }
69 
70 
71 // Verify no warning for an unknown struct object.
gaxp(Ax * p)72 NOIPA void gaxp (Ax *p)
73 {
74   p->a[0] = 0;
75   p->a[3] = 0;
76   p->a[9] = 0;
77 }
78 
79 
80 // Verify no warning for an extern struct object whose array may be
81 // initialized to any number of elements.
82 extern Ax axx;
83 
gaxx()84 NOIPA void gaxx ()
85 {
86   axx.a[0] = 0;
87   axx.a[3] = 0;
88   axx.a[9] = 0;
89 }
90 
91 // Exercise zero-length array members.
92 
93 struct A0
94 {
95   char n;
96   char a[0];                    // { dg-message "at offset \[0-2\] to object 'A0::a' with size 0 declared here" "note: trailing zero-length array" }
97 };
98 
99 // Verify warning for a definition with no initializer.
100 A0 a0_;
101 
ga0_()102 NOIPA void ga0_ ()
103 {
104   a0_.a[0] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
105   a0_.a[1] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
106   a0_.a[2] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
107 }
108 
109 // Verify warning for access to a definition with an initializer that doesn't
110 // initialize the flexible array member.
111 A0 a00 = { 0 };
112 
ga00()113 NOIPA void ga00 ()
114 {
115   a00.a[0] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
116   a00.a[1] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
117   a00.a[2] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
118 }
119 
120 // Verify warning for access to a definition with an initializer that
121 // initializes the flexible array member to empty.
122 A0 a00_ = { 0, { } };
123 
ga00_()124 NOIPA void ga00_ ()
125 {
126   a00_.a[0] = 0;                // { dg-warning "\\\[-Wstringop-overflow" }
127   a00_.a[1] = 0;                // { dg-warning "\\\[-Wstringop-overflow" }
128   a00_.a[2] = 0;                // { dg-warning "\\\[-Wstringop-overflow" }
129 }
130 
131 // The following are rejected with
132 //   error: too many initializers for 'char [0]'
133 // A0 a01 = { 1, { 0 } };
134 // A0 a02 = { 2, { 1, 0 } };
135 
136 
137 // Verify no warning for an unknown struct object.
ga0p(A0 * p)138 NOIPA void ga0p (A0 *p)
139 {
140   p->a[0] = 0;
141   p->a[3] = 0;
142   p->a[9] = 0;
143 }
144 
145 
146 // Verify warning for an extern struct object which (unlike a true
147 // flexible array member) may not be initialized.
148 extern A0 a0x;
149 
ga0x()150 NOIPA void ga0x ()
151 {
152   a0x.a[0] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
153   a0x.a[3] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
154   a0x.a[9] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
155 }
156 
157 
158 // Exercise trailing one-element array members.
159 
160 struct A1
161 {
162   char n;
163   char a[1];                    // { dg-message "at offset \[1-9\] to object 'A1::a' with size 1 declared here" "note: trailing one-element array" }
164 };
165 
166 // Verify warning for a definition with no initializer.
167 A1 a1_;
168 
ga1_()169 NOIPA void ga1_ ()
170 {
171   a1_.a[0] = 0;
172   a1_.a[1] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
173   a1_.a[2] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
174 }
175 
176 // Verify warning for access to a definition with an initializer that doesn't
177 // initialize the one-element array member.
178 A1 a1__ = { 0 };
179 
ga1__()180 NOIPA void ga1__ ()
181 {
182   a1__.a[0] = 0;
183   a1__.a[1] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
184   a1__.a[2] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
185 }
186 
187 // Verify warning for access to a definition with an initializer that
188 // initializes the one-element array member to empty.
189 A1 a1_0 = { 0, { } };
190 
ga1_0_()191 NOIPA void ga1_0_ ()
192 {
193   a1_0.a[0] = 0;
194   a1_0.a[1] = 0;                // { dg-warning "\\\[-Wstringop-overflow" }
195   a1_0.a[2] = 0;                // { dg-warning "\\\[-Wstringop-overflow" }
196 }
197 
198 // Verify warning for access to a definition with an initializer that
199 // initializes the one-element array member.
200 A1 a1_1 = { 0, { 1 } };
201 
ga1_1()202 NOIPA void ga1_1 ()
203 {
204   a1_1.a[0] = 0;
205   a1_1.a[1] = 0;                // { dg-warning "\\\[-Wstringop-overflow" }
206   a1_1.a[2] = 0;                // { dg-warning "\\\[-Wstringop-overflow" }
207 }
208 
209 
210 // Verify no warning for an unknown struct object.
ga1p(A1 * p)211 NOIPA void ga1p (A1 *p)
212 {
213   p->a[0] = 0;
214   p->a[3] = 0;
215   p->a[9] = 0;
216 }
217 
218 
219 // Verify warning for an extern struct object.  Similar to the zero-length
220 // array case, a one-element trailing array can be initialized to at most
221 // a single element.
222 extern A1 a1x;
223 
ga1x()224 NOIPA void ga1x ()
225 {
226   a1x.a[0] = 0;
227   a1x.a[3] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
228   a1x.a[9] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
229 }
230 
231 // Exercise interior one-element array members (verify they're not
232 // treated as trailing.
233 
234 struct A1i
235 {
236   char n;
237   char a[1];                    // { dg-message "at offset \[1-9\] to object 'A1i::a' with size 1 declared here" "note: interior one-element array" }
238   char x;
239 };
240 
241 // Verify warning for a definition with no initializer.
242 A1i a1i_;
243 
ga1i_()244 NOIPA void ga1i_ ()
245 {
246   a1i_.a[0] = 0;
247   a1i_.a[1] = 0;                // { dg-warning "\\\[-Wstringop-overflow" }
248   a1i_.a[2] = 0;                // { dg-warning "\\\[-Wstringop-overflow" }
249 }
250 
251 // Verify warning for access to a definition with an initializer that doesn't
252 // initialize the one-element array member.
253 A1i a1i__ = { 0 };
254 
ga1i__()255 NOIPA void ga1i__ ()
256 {
257   a1i__.a[0] = 0;
258   a1i__.a[1] = 0;                // { dg-warning "\\\[-Wstringop-overflow" }
259   a1i__.a[2] = 0;                // { dg-warning "\\\[-Wstringop-overflow" }
260 }
261 
262 // Verify warning for access to a definition with an initializer that
263 // initializes the one-element array member to empty.
264 A1 a1i_0 = { 0, { } };
265 
ga1i_0_()266 NOIPA void ga1i_0_ ()
267 {
268   a1i_0.a[0] = 0;
269   a1i_0.a[1] = 0;               // { dg-warning "\\\[-Wstringop-overflow" }
270   a1i_0.a[2] = 0;               // { dg-warning "\\\[-Wstringop-overflow" }
271 }
272 
273 // Verify warning for access to a definition with an initializer that
274 // initializes the one-element array member.
275 A1 a1i_1 = { 0, { 1 } };
276 
ga1i_1()277 NOIPA void ga1i_1 ()
278 {
279   a1i_1.a[0] = 0;
280   a1i_1.a[1] = 0;               // { dg-warning "\\\[-Wstringop-overflow" }
281   a1i_1.a[2] = 0;               // { dg-warning "\\\[-Wstringop-overflow" }
282 }
283 
284 
285 // Verify no warning for an unknown struct object.
ga1ip(A1i * p)286 NOIPA void ga1ip (A1i *p)
287 {
288   p->a[0] = 0;
289   p->a[3] = 0;                  // { dg-warning "\\\[-Wstringop-overflow" }
290   p->a[9] = 0;                  // { dg-warning "\\\[-Wstringop-overflow" }
291 }
292 
293 
294 // Verify no warning for an extern struct object.
295 extern A1i a1ix;
296 
ga1ix()297 NOIPA void ga1ix ()
298 {
299   a1ix.a[0] = 0;
300   a1ix.a[3] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
301   a1ix.a[9] = 0;                 // { dg-warning "\\\[-Wstringop-overflow" }
302 }
303 
304 
305 // Verify non-POD classes with flexible array members.
306 
307 struct Bx
308 {
309   char n;
310   char a[];                     // { dg-message "at offset 0 to object 'Bx::a' declared here" "note: flexarray class member" }
311 
312   // Verify the warning for a constant.
BxBx313   Bx () { a[0] = 0; }           // { dg-warning "\\\[-Wstringop-overflow" }
314 
315   // And also for a non-constant.  Regardless of the subscript, the array
316   // of the object in function gxi() below has a zero size.
BxBx317   Bx (int i) { a[i] = 0; }      // { dg-warning "\\\[-Wstringop-overflow" }
318 };
319 
gbx(void)320 NOIPA void gbx (void)
321 {
322   struct Bx bx;
323   sink (&bx);
324 }
325 
gbxi(int i)326 NOIPA void gbxi (int i)
327 {
328   struct Bx bxi (i);
329   sink (&bxi);
330 }
331 
332 struct B0
333 {
334   char n;
335   char a[0];                    // { dg-message "at offset 0 to object 'B0::a' with size 0 declared here" "note: zero-length trailing array class member" }
336 
B0B0337   B0 () { a[0] = 0; }           // { dg-warning "\\\[-Wstringop-overflow" }
338 };
339 
340 
gb0(void)341 NOIPA void gb0 (void)
342 {
343   struct B0 b0;
344   sink (&b0);
345 }
346 
347 
348 struct B1
349 {
350   char n;
351   char a[1];                    // { dg-message "at offset 1 to object 'B1::a' with size 1 declared here" "note: one-element trailing array class member" }
352 
B1B1353   B1 () { a[1] = 0; }           // { dg-warning "\\\[-Wstringop-overflow" }
354 };
355 
gb1(void)356 NOIPA void gb1 (void)
357 {
358   struct B1 b1;
359   sink (&b1);
360 }
361 
362 
363 struct B123
364 {
365   char a[123];                  // { dg-message "at offset 123 to object 'B123::a' with size 123 declared here" "note: large trailing array class member" }
366 
B123B123367   B123 () { a[123] = 0; }       // { dg-warning "\\\[-Wstringop-overflow" }
368 };
369 
gb123(void)370 NOIPA void gb123 (void)
371 {
372   struct B123 b123;
373   sink (&b123);
374 }
375 
376 
377 struct B234
378 {
379   char a[234];                  // { dg-message "at offset 234 to object 'B234::a' with size 234 declared here" "note: large trailing array class member" }
380 
B234B234381   B234 (int i) { a[i] = 0; }    // { dg-warning "\\\[-Wstringop-overflow" }
382 };
383 
g234(void)384 NOIPA void g234 (void)
385 {
386   struct B234 b234 (234);
387   sink (&b234);
388 }
389