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