1 /* Exercise that -Warray-bounds is issued for out-of-bounds offsets
2    in calls to built-in functions.
3    { dg-do compile }
4    { dg-options "-O2 -Wno-stringop-overflow -Warray-bounds -ftrack-macro-expansion=0" }  */
5 
6 #include "../gcc.dg/range.h"
7 
8 #if __cplusplus
9 #  define restrict __restrict
10 extern "C" {
11 #endif
12 
13 extern void* memcpy (void* restrict, const void* restrict, size_t);
14 extern void* mempcpy (void* restrict, const void* restrict, size_t);
15 extern void* memmove (void*, const void*, size_t);
16 
17 extern char* stpcpy (char* restrict, const char* restrict);
18 
19 extern char* strcat (char* restrict, const char* restrict);
20 extern char* strcpy (char* restrict, const char* restrict);
21 extern char* strncpy (char* restrict, const char* restrict, size_t);
22 
23 #if __cplusplus
24 }   /* extern "C" */
25 #endif
26 
27 void sink (void*, ...);
28 
29 #define CAT(x, y)      x ## y
30 #define CONCAT(x, y)   CAT (x, y)
31 #define UNIQUE_NAME(x) CONCAT(x, __LINE__)
32 
33 #define T(type, N, dst, src, n) do {		\
34     extern type UNIQUE_NAME (a)[N];		\
35     type *a = UNIQUE_NAME (a);			\
36     type *pd = (dst);				\
37     const type *ps = (src);			\
38     FUNC (pd, ps, n);				\
39     sink (a, pd, ps);				\
40   } while (0)
41 
42 
test_memcpy_bounds(char * d,const char * s,size_t n)43 void test_memcpy_bounds (char *d, const char *s, size_t n)
44 {
45 #define FUNC memcpy
46 
47   /* Verify that invalid offsets into an array of known size are
48      detected.  */
49 
50   T (char, 1, a + SR (DIFF_MIN, -1), s, n);     /* { dg-warning "offset \\\[-\[0-9\]+, -1] is out of the bounds \\\[0, 1] of object \[^\n\r]* with type .char ?\\\[1]" } */
51   T (char, 1, a + SR (-2, -1), s, n);     /* { dg-warning "offset \\\[-2, -1] is out of the bounds \\\[0, 1] of object" } */
52   T (char, 1, a + SR (-2, 0), s, n);
53 
54   T (char, 1, a + UR (0, 1), s, n);
55   T (char, 1, a + UR (0, 2), s, n);
56   T (char, 1, a + UR (1, 2), s, n);
57   T (char, 1, a + UR (2, 3), s, n);       /* { dg-warning "offset \\\[2, 3] is out of the bounds \\\[0, 1] of object " } */
58   T (char, 1, a + UR (2, DIFF_MAX), s, n);  /* { dg-warning "offset \\\[2, \[0-9\]+] is out of the bounds \\\[0, 1] of object " "memcpy" } */
59 
60   /* Offsets in excess of DIFF_MAX are treated as negative even if
61      they appear as large positive in the source.  It would be nice
62      if they retained their type but unfortunately that's not how
63      it works so be prepared for both in case it even gets fixed.  */
64   T (char, 1, a + UR (3, SIZE_MAX - 1), s, n);   /* { dg-warning "offset \\\[3, -?\[0-9\]+] is out of the bounds \\\[0, 1] of object" "memcpy" } */
65 
66   /* Verify that invalid offsets into an array of unknown size are
67      detected.  */
68   extern char arr[];
69   T (char, 1, arr + SR (DIFF_MIN,             0), s, n);
70   T (char, 1, arr + SR (DIFF_MIN + 1,        -1), s, n);   /* { dg-warning "offset \\\[-\[0-9\]+, -1] is out of the bounds of object " "memcpy" } */
71   T (char, 1, arr + SR (DIFF_MIN,             1), s, n);
72   T (char, 1, arr + SR (DIFF_MIN,      DIFF_MAX), s, n);
73   T (char, 1, arr + SR (       -2,           -1), s, n);   /* { dg-warning "offset \\\[-2, -1] is out of the bounds of object " "memcpy" } */
74   T (char, 1, arr + SR (       -1,            0), s, n);
75   T (char, 1, arr + SR (       -1,            1), s, n);
76   T (char, 1, arr + SR (       -1, DIFF_MAX - 1), s, n);
77   T (char, 1, arr + SR (        0,            1), s, n);
78   T (char, 1, arr + SR (        0, DIFF_MAX - 1), s, n);
79   T (char, 1, arr + SR (        1,            2), s, n);
80   T (char, 1, arr + SR (        1, DIFF_MAX - 1), s, n);
81 
82   /* Verify that all offsets via a pointer to an uknown object are
83      accepted.  */
84 
85   /* Negative indices between [DIFF_MIN, DIFF_MAX] are valid since
86      the pointer to which the offset is applied can be at a positive
87      offset from the beginning of an object.  */
88   T (char, 1, d + SR (DIFF_MIN,             0), s, n);
89   T (char, 1, d + SR (DIFF_MIN,            -1), s, n);
90   T (char, 1, d + SR (DIFF_MIN,             1), s, n);
91   T (char, 1, d + SR (DIFF_MIN,  DIFF_MAX - 1), s, n);
92   T (char, 1, d + SR (       -2,           -1), s, n);
93   T (char, 1, d + SR (       -1,            0), s, n);
94   T (char, 1, d + SR (       -1,            1), s, n);
95   T (char, 1, d + SR (       -1, DIFF_MAX - 1), s, n);
96   T (char, 1, d + SR (        0,            1), s, n);
97   T (char, 1, d + SR (        0, DIFF_MAX - 1), s, n);
98   T (char, 1, d + SR (        1,            2), s, n);
99   T (char, 1, d + SR (        1, DIFF_MAX - 1), s, n);
100 }
101 
102 /* Verify offsets in an anti-range.  */
103 
test_memcpy_bounds_anti_range(char * d,const char * s,size_t n)104 void test_memcpy_bounds_anti_range (char *d, const char *s, size_t n)
105 {
106   T (char, 9, a, a + SAR (-2, -1), 3);
107   T (char, 9, a, a + SAR (-1,  1), 3);
108   T (char, 9, a, a + SAR ( 0,  1), 3);
109   T (char, 9, a, a + SAR ( 0,  2), 3);
110   T (char, 9, a, a + SAR ( 0,  3), 3);
111   T (char, 9, a, a + SAR ( 0,  4), 3);
112   T (char, 9, a, a + SAR ( 0,  5), 3);
113   /* The initial source range is valid but the final range after the access
114      has complete cannot be.  The value mentioned in the warning is the final
115      offset, i.e., 7 + 3.  Including the whole final range because would be
116      confusing (the upper bound would either be negative or a very large
117      positive number) so only the lower bound is included.  */
118   T (char, 9, a, a + SAR ( 0,  6), 3);   /* { dg-warning "forming offset 10 is out of the bounds \\\[0, 9] of object " "memcpy" } */
119 
120   /* This fails because the offset isn't represented as an SSA_NAME
121      but rather as a GIMPLE_PHI (offset, 0).  With some effort it is
122      possible to extract the range from the PHI but it's not implemented
123      (yet).  */
124   T (char, 9, a, a + SAR ( 1,  6), 3);   /* { dg-warning "forming offset \\\[9, 0] is out of the bounds \\\[0, 9] of object " "memcpy" { xfail *-*-* } } */
125 
126   /* The range of offsets is the union of [0, 1] and [7, PTRDIFF_MAX]
127      of which the first subrange is valid and thus no warming for memcpy
128      is issued.  Similarly for the next test.  */
129   T (char, 9, a, a + SAR ( 2,  6), 3);
130   T (char, 9, a, a + SAR ( 3,  6), 3);
131 
132   T (char, 9, a, a + SAR (-1,  7), 3);   /* { dg-warning "forming offset \\\[10, 11] is out of the bounds \\\[0, 9] of object " "memcpy" } */
133   T (char, 9, a, a + SAR (-2,  8), 3);   /* { dg-warning "forming offset \\\[10, 12] is out of the bounds \\\[0, 9] of object " "memcpy" } */
134   T (char, 9, a, a + SAR (-3,  7), 5);   /* { dg-warning "forming offset \\\[10, 13] is out of the bounds \\\[0, 9] of object " "memcpy" } */
135 
136   T (char, 9, a + SAR (-2, -1), a, 3);
137   T (char, 9, a + SAR (-1,  1), a, 3);
138   T (char, 9, a + SAR ( 0,  1), a, 3);
139   T (char, 9, a + SAR ( 0,  2), a, 3);
140   T (char, 9, a + SAR ( 0,  3), a, 3);
141   T (char, 9, a + SAR ( 0,  6), a, 3);   /* { dg-warning "forming offset 10 is out of the bounds \\\[0, 9] of object " "memcpy" } */
142   T (char, 9, a + SAR (-1,  7), a, 3);   /* { dg-warning "forming offset \\\[10, 11] is out of the bounds \\\[0, 9] of object " "memcpy" } */
143   T (char, 9, a + SAR (-2,  8), a, 3);   /* { dg-warning "forming offset \\\[10, 12] is out of the bounds \\\[0, 9] of object " "memcpy" } */
144 
145   ptrdiff_t i = SAR (DIFF_MIN + 1, DIFF_MAX - 4);
146   T (char, 1, d, d + SAR (DIFF_MIN + 3, DIFF_MAX - 1), 3);
147   T (char, 1, d, d + SAR (DIFF_MIN + 3, DIFF_MAX - 3), 5);
148 }
149 
150 /* Verify that pointer overflow in the computation done by memcpy
151    (i.e., offset + size) is detected and diagnosed.  */
152 
test_memcpy_overflow(char * d,const char * s,size_t n)153 void test_memcpy_overflow (char *d, const char *s, size_t n)
154 {
155   extern char arr[];
156 
157   /* Verify that offset overflow involving an array of unknown size
158      but known access size is detected.  This works except with small
159      sizes that are powers of 2 due to bug .  */
160   T (char, 1, arr + SR (DIFF_MAX - 1, DIFF_MAX), s, 1);
161   T (char, 1, arr + SR (DIFF_MAX - 1, DIFF_MAX), s, 2);  /* { dg-warning "pointer overflow between offset \\\[\[0-9\]+, \[0-9\]+] and size 2 accessing array " "bug " { xfail *-*-* } } */
162   T (char, 1, arr + SR (DIFF_MAX - 2, DIFF_MAX), s, 3);  /* { dg-warning "pointer overflow between offset \\\[\[0-9\]+, \[0-9\]+] and size 3 accessing array " "memcpy" } */
163   T (char, 1, arr + SR (DIFF_MAX - 4, DIFF_MAX), s, 5);  /* { dg-warning "pointer overflow between offset \\\[\[0-9\]+, \[0-9\]+] and size 5 accessing array " "memcpy" } */
164 }
165 
test_memcpy_bounds_memarray_range(void)166 void test_memcpy_bounds_memarray_range (void)
167 {
168 #undef TM
169 #define TM(mem, dst, src, n)			\
170   do {						\
171     struct MA { char a5[5]; int i; } ma;	\
172     sink (&ma);   /* Initialize arrays.  */	\
173     memcpy (dst, src, n);			\
174     sink (&ma);					\
175   } while (0)
176 
177   ptrdiff_t i = SR (1, 2);
178 
179   TM (ma.a5, ma.a5 + i, ma.a5, 1);
180   TM (ma.a5, ma.a5 + i, ma.a5, 3);
181   TM (ma.a5, ma.a5 + i, ma.a5, 5);
182   TM (ma.a5, ma.a5 + i, ma.a5, 7);     /* diagnosed with -Warray-bounds=2 */
183 }
184 
test_memmove_bounds(char * d,const char * s,size_t n)185 void test_memmove_bounds (char *d, const char *s, size_t n)
186 {
187 #undef FUNC
188 #define FUNC memmove
189 
190     T (char, 1, a + SR (DIFF_MIN + 1, -1), s, n);     /* { dg-warning "offset \\\[-\[0-9\]+, -1] is out of the bounds \\\[0, 1] of object \[^\n\r]+ with type .char ?\\\[1]" } */
191   T (char, 1, a + SR (-2, -1), s, n);     /* { dg-warning "offset \\\[-2, -1] is out of the bounds \\\[0, 1] of object" } */
192   T (char, 1, a + SR (-2, 0), s, n);
193 
194   const int *pi = (const int*)s;
195   T (int,  2, a + SR (-1, 1), pi, n);
196   T (int,  2, a + SR (-1, 2), pi, n);
197   T (int,  2, a + SR ( 0, 2), pi, n);
198   T (int,  2, a + SR ( 0, 3), pi, n);
199   T (int,  2, a + SR ( 1, 3), pi, n);
200   T (int,  2, a + SR ( 2, 3), pi, n);
201 
202   const int32_t *pi32 = (const int32_t*)s;
203   T (int32_t, 2, a + SR ( 3, 4), pi32, n);      /* { dg-warning "offset \\\[12, 16] is out of the bounds \\\[0, 8] of object .\[^\n\r]+. with type .int32_t ?\\\[2]." } */
204 }
205 
206 
test_mempcpy_bounds(char * d,const char * s,size_t n)207 void test_mempcpy_bounds (char *d, const char *s, size_t n)
208 {
209 #undef FUNC
210 #define FUNC mempcpy
211 
212   /* Verify that invalid offsets into an array of known size are
213      detected.  */
214 
215   T (char, 1, a + SR (DIFF_MIN, -1), s, n);     /* { dg-warning "offset \\\[-\[0-9\]+, -1] is out of the bounds"  "mempcpy" } */
216 T (char, 1, a + SR (-2, -1), s, n);     /* { dg-warning "offset \\\[-2, -1] is out of the bounds"  "mempcpy" } */
217   T (char, 1, a + SR (-2, 0), s, n);
218 
219   T (char, 1, a + UR (0, 1), s, n);
220   T (char, 1, a + UR (0, 2), s, n);
221   T (char, 1, a + UR (1, 2), s, n);
222   T (char, 1, a + UR (2, 3), s, n);       /* { dg-warning "offset \\\[2, 3] is out of the bounds \\\[0, 1] of object "  "mempcpy" } */
223   T (char, 1, a + UR (2, DIFF_MAX), s, n);  /* { dg-warning "offset \\\[2, \[0-9\]+] is out of the bounds \\\[0, 1] of object"  "mempcpy" } */
224 
225   /* Offsets in excess of DIFF_MAX are treated as negative even if
226      they appear as large positive in the source.  It would be nice
227      if they retained their type but unfortunately that's not how
228      it works so be prepared for both in case it ever gets fixed.  */
229   T (char, 1, a + UR (3, SIZE_MAX), s, n);   /* { dg-warning "offset \\\[3, -?\[0-9\]+] is out of the bounds \\\[0, 1] of object "  "mempcpy" } */
230 
231   /* Verify that invalid offsets into an array of unknown size are
232      detected.  */
233   extern char arr[];
234   T (char, 1, arr + SR (DIFF_MIN,         0), s, n);
235   T (char, 1, arr + SR (DIFF_MIN,        -1), s, n);   /* { dg-warning "offset \\\[-\[0-9\]+, -1] is out of the bounds of object"  "mempcpy" } */
236   T (char, 1, arr + SR (DIFF_MIN,         1), s, n);
237   T (char, 1, arr + SR (DIFF_MIN, DIFF_MAX), s, n);
238   T (char, 1, arr + SR (       -2,        -1), s, n);   /* { dg-warning "offset \\\[-2, -1] is out of the bounds of object"  "mempcpy" } */
239   T (char, 1, arr + SR (       -1,         0), s, n);
240   T (char, 1, arr + SR (       -1,         1), s, n);
241   T (char, 1, arr + SR (       -1, DIFF_MAX), s, n);
242   T (char, 1, arr + SR (        0,         1), s, n);
243   T (char, 1, arr + SR (        0, DIFF_MAX), s, n);
244   T (char, 1, arr + SR (        1,         2), s, n);
245   T (char, 1, arr + SR (        1, DIFF_MAX), s, n);
246 
247   /* Verify that all offsets via a pointer to an uknown object are
248      accepted.  */
249 
250   /* Negative indices between [DIFF_MIN, DIFF_MAX] are valid since
251      the pointer to which the offset is applied can be at a positive
252      offset from the beginning of an object.  */
253   T (char, 1, d + SR (DIFF_MIN,         0), s, n);
254   T (char, 1, d + SR (DIFF_MIN,        -1), s, n);
255   T (char, 1, d + SR (DIFF_MIN,         1), s, n);
256   T (char, 1, d + SR (DIFF_MIN, DIFF_MAX), s, n);
257   T (char, 1, d + SR (       -2,        -1), s, n);
258   T (char, 1, d + SR (       -1,         0), s, n);
259   T (char, 1, d + SR (       -1,         1), s, n);
260   T (char, 1, d + SR (       -1, DIFF_MAX), s, n);
261   T (char, 1, d + SR (        0,         1), s, n);
262   T (char, 1, d + SR (        0, DIFF_MAX), s, n);
263   T (char, 1, d + SR (        1,         2), s, n);
264   T (char, 1, d + SR (        1, DIFF_MAX), s, n);
265 }
266 
267 #define TI(type, N, init, dst, src) do {	\
268     type UNIQUE_NAME (a)[N] = init;		\
269     type *a = UNIQUE_NAME (a);			\
270     type *pd = (dst);				\
271     const type *ps = (src);			\
272     FUNC (pd, ps);				\
273     sink (a, pd, ps, s);			\
274   } while (0)
275 
test_strcpy_bounds(char * d,const char * s)276 void test_strcpy_bounds (char *d, const char *s)
277 {
278 #undef FUNC
279 #define FUNC strcpy
280 
281   ptrdiff_t i;
282 
283   TI (char, 1, "",   a, a + SR (DIFF_MIN, 0));
284   TI (char, 1, "",   a, a + SR (-1, 0));
285   TI (char, 1, "",   a, a + SR (-1, 1));
286   TI (char, 1, "",   a, a + SR (0, 1));
287   TI (char, 1, "",   a, a + SR (0, DIFF_MAX - 1));
288   TI (char, 2, "0",  a, a + SR (0, DIFF_MAX - 1));
289   TI (char, 2, "0",  a, a + SR (1, DIFF_MAX - 1));
290   /* The following needs a warning for reading past the end.  */
291   TI (char, 2, "0",  a, a + SR (2, DIFF_MAX - 1));
292   TI (char, 2, "0",  a, a + SR (3, DIFF_MAX - 1));   /* { dg-warning "offset \\\[3, \[0-9\]+] is out of the bounds \\\[0, 2] of object \[^\n\r\]+ with type .char ?\\\[2\\\]."  "strcpy" } */
293 
294   TI (char, 3, "01", a, a + SR (0, DIFF_MAX - 1));
295   TI (char, 3, "01", a, a + SR (1, DIFF_MAX - 1));
296   TI (char, 3, "01", a, a + SR (2, DIFF_MAX - 1));
297   /* The following needs a warning for reading past the end.  */
298   TI (char, 3, "01", a, a + SR (3, DIFF_MAX - 1));
299   TI (char, 3, "01", a, a + SR (4, DIFF_MAX - 1));   /* { dg-warning "offset \\\[4, \[0-9\]+] is out of the bounds \\\[0, 3] of object \[^\n\r\]+ with type .char ?\\\[3\\\]."  "strcpy" } */
300 
301   TI (char, 4, "012", a, a + SR (DIFF_MAX - 2, DIFF_MAX - 1));   /* { dg-warning "offset \\\[\[0-9\]+, \[0-9\]+] is out of the bounds \\\[0, 4] of object \[^\n\r\]+ with type .char ?\\\[4\\\]."  "strcpy" } */
302 
303 
304   TI (char, 1, "", a + SR (DIFF_MIN, 0), s);
305   TI (char, 1, "", a + SR (-1, 0), s);
306   TI (char, 1, "", a + SR (-1, 1), s);
307   TI (char, 1, "", a + SR (0, 1), s);
308   TI (char, 1, "", a + SR (0, DIFF_MAX - 1), s);
309   TI (char, 2, "", a + SR (0, DIFF_MAX - 1), s);
310   TI (char, 2, "", a + SR (1, DIFF_MAX - 1), s);
311   /* The following is diagnosed not because the initial source offset
312      it out of bounds (it isn't) but because the final source offset
313      after the access has completed, is.  It would be clearer if
314      the warning mentioned the final offset.  */
315   TI (char, 2, "", a + SR (2, DIFF_MAX - 1), s);   /* { dg-warning "forming offset 3 is out of the bounds \\\[0, 2] of object \[^\n\r\]+ with type .char ?\\\[2\\\]."  "strcpy" } */
316   TI (char, 2, "", a + SR (3, DIFF_MAX - 1), s);   /* { dg-warning "offset \\\[3, \[0-9\]+] is out of the bounds \\\[0, 2] of object \[^\n\r\]+ with type .char ?\\\[2\\\]."  "strcpy" } */
317 
318   TI (char, 3, "", a + SR (0, DIFF_MAX - 1), s);
319   TI (char, 3, "", a + SR (1, DIFF_MAX - 1), s);
320   TI (char, 3, "", a + SR (2, DIFF_MAX - 1), s);
321   TI (char, 3, "", a + SR (3, DIFF_MAX - 1), s);   /* { dg-warning "forming offset 4 is out of the bounds \\\[0, 3] of object \[^\n\r\]+ with type .char ?\\\[3\\\]."  "strcpy" } */
322   TI (char, 3, "", a + SR (4, DIFF_MAX - 1), s);   /* { dg-warning "offset \\\[4, \[0-9\]+] is out of the bounds \\\[0, 3] of object \[^\n\r\]+ with type .char ?\\\[3\\\]."  "strcpy" } */
323 
324   TI (char, 4, "", a + SR (DIFF_MAX - 2, DIFF_MAX - 1), s);   /* { dg-warning "offset \\\[\[0-9\]+, \[0-9\]+] is out of the bounds \\\[0, 4] of object \[^\n\r\]+ with type .char ?\\\[4\\\]."  "strcpy" } */
325 }
326 
327 struct MA
328 {
329   int i;
330   char a5[5];
331   char a11[11];
332 };
333 
334 struct MA2
335 {
336   struct MA ma3[3];
337   struct MA ma5[5];
338   char ax[];
339 };
340 
341 struct MA3
342 {
343   struct MA2 ma5[3];
344   struct MA2 ma7[7];
345 };
346 
test_strcpy_bounds_memarray_range(void)347 void test_strcpy_bounds_memarray_range (void)
348 {
349 #undef TM
350 #define TM(mem, init, dst, src)			\
351   do {						\
352     struct MA ma;				\
353     strcpy (ma.mem, init);			\
354     strcpy (dst, src);				\
355     sink (&ma);					\
356   } while (0)
357 
358   ptrdiff_t i = SR (1, 2);
359 
360   TM (a5, "0",    ma.a5 + i, ma.a5);
361   TM (a5, "01",   ma.a5 + i, ma.a5);
362   TM (a5, "012",  ma.a5 + i, ma.a5);
363   TM (a5, "0123", ma.a5 + i, ma.a5);     /* { dg-warning "offset 10 from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]. at offset 4" "strcpy" } */
364 
365   TM (a11, "0",       ma.a5, ma.a11);
366   TM (a11, "01",      ma.a5, ma.a11);
367   TM (a11, "012",     ma.a5, ma.a11);
368   TM (a11, "0123",    ma.a5, ma.a11);
369   TM (a11, "01234",   ma.a5, ma.a11);    /* { dg-warning "offset 10 from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]' at offset 4" } */
370   TM (a11, "012345",  ma.a5, ma.a11);    /* { dg-warning "offset \\\[10, 11] from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]' at offset 4" } */
371   TM (a11, "0123456", ma.a5, ma.a11);    /* { dg-warning "offset \\\[10, 12] from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]' at offset 4" } */
372 
373   TM (a11, "0123456", ma.a11 + i, "789abcd");
374 }
375 
test_strcpy_bounds_memarray_var(struct MA * pma,struct MA2 * pma2,struct MA3 * pma3,const char * s,size_t n)376 void test_strcpy_bounds_memarray_var (struct MA *pma,
377 				      struct MA2 *pma2,
378 				      struct MA3 *pma3,
379 				      const char *s, size_t n)
380 {
381 #undef TM
382 #define TM(dst, src) do {			\
383     strcpy (dst, src);				\
384     sink (dst, src);				\
385   } while (0)
386 
387   TM (pma->a5, s);
388   TM (pma->a5 + 0, s);
389   TM (pma->a5 + 1, s);
390   TM (pma->a5 + 4, s);
391 
392   /* The following forms a pointer during the call that's outside
393      the bounds of the array it was derived from (pma->a5) so
394      it should be diagnosed but the representation of the pointer
395      addition doesn't contain information to distinguish it from
396      the valid pma->a11 + 1 so this is an XFAIL.  */
397   TM (pma->a5 + 5, s);                 /* { dg-warning "offset 17 from the object at .pma. is out of the bounds of .struct MA." "strcpy" { xfail *-*-* } } */
398 
399   /* The following also forms an out-of-bounds pointer but similar
400      to the above, there is no reliable way to distinguish it from
401      (char*)&pma[1].i + 1 so this too is not diagnosed.  */
402   TM (pma->a5 + sizeof *pma + 1, s);   /* { dg-warning "offset 17 from the object at .pma. is out of the bounds of .struct MA." "strcpy" { xfail *-*-* } } */
403 
404   TM (pma->a5 - 1, s);   /* { dg-warning "offset -1 from the object at .pma. is out of the bounds of .struct MA." "strcpy" { xfail *-*-* } } */
405 
406   TM (pma[1].a5, s);
407   TM (pma[2].a5 + 0, s);
408   TM (pma[3].a5 + 1, s);
409   TM (pma[4].a5 + 4, s);
410 
411 
412   extern struct MA3 ma3[3];
413   TM (ma3[0].ma5[0].ma3[0].a5 + 6, s);
414 }
415