]>
Commit | Line | Data |
---|---|---|
cc8bea0a MS |
1 | /* Exercise that -Warray-bounds is issued for out-of-bounds offsets |
2 | in calls to built-in functions. | |
3 | { dg-do compile } | |
af3fa359 | 4 | { dg-options "-O2 -Wno-stringop-overflow -Warray-bounds -ftrack-macro-expansion=0" } */ |
cc8bea0a MS |
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 | ||
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. */ | |
5e27f0d5 | 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" } */ |
cc8bea0a MS |
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 | ||
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. */ | |
6889a3ac | 118 | T (char, 9, a, a + SAR ( 0, 6), 3); /* { dg-warning "forming offset 9 is out of the bounds \\\[0, 9] of object " "memcpy" } */ |
cc8bea0a MS |
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 | ||
56735d40 MS |
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); | |
cc8bea0a | 131 | |
6889a3ac MS |
132 | 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" } */ |
133 | T (char, 9, a, a + SAR (-2, 8), 3); /* { dg-warning "offset \\\[9, 11] is out of the bounds \\\[0, 9] of object " "memcpy" } */ | |
134 | 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" } */ | |
cc8bea0a MS |
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); | |
6889a3ac MS |
141 | T (char, 9, a + SAR ( 0, 6), a, 3); /* { dg-warning "forming offset 9 is out of the bounds \\\[0, 9] of object " "memcpy" } */ |
142 | 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" } */ | |
143 | T (char, 9, a + SAR (-2, 8), a, 3); /* { dg-warning "offset \\\[9, 11] is out of the bounds \\\[0, 9] of object " "memcpy" } */ | |
cc8bea0a MS |
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 | ||
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); | |
a1108556 | 161 | T (char, 1, arr + SR (DIFF_MAX - 1, DIFF_MAX), s, 2); /* { dg-warning "\\\[-Warray-bounds" } */ |
cc8bea0a MS |
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 | ||
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); | |
a1108556 | 181 | TM (ma.a5, ma.a5 + i, ma.a5, 5); /* { dg-warning "\\\[-Warray-bounds" } */ |
cc8bea0a MS |
182 | TM (ma.a5, ma.a5 + i, ma.a5, 7); /* diagnosed with -Warray-bounds=2 */ |
183 | } | |
184 | ||
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 | ||
12b38cca EB |
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]." } */ | |
cc8bea0a MS |
204 | } |
205 | ||
206 | ||
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. */ | |
5e27f0d5 | 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" } */ |
cc8bea0a MS |
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 | ||
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)); | |
3942060c MS |
290 | /* The warning below isn't the most accurate because while reading |
291 | from it is invalid, the offset that refers just past the end of | |
292 | the source array is strictly valid. */ | |
293 | 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]'" } */ | |
cc8bea0a MS |
294 | 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" } */ |
295 | ||
296 | TI (char, 3, "01", a, a + SR (0, DIFF_MAX - 1)); | |
297 | TI (char, 3, "01", a, a + SR (1, DIFF_MAX - 1)); | |
298 | TI (char, 3, "01", a, a + SR (2, DIFF_MAX - 1)); | |
3942060c | 299 | 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]'" } */ |
cc8bea0a MS |
300 | 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" } */ |
301 | ||
302 | 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" } */ | |
303 | ||
304 | ||
305 | TI (char, 1, "", a + SR (DIFF_MIN, 0), s); | |
306 | TI (char, 1, "", a + SR (-1, 0), s); | |
307 | TI (char, 1, "", a + SR (-1, 1), s); | |
308 | TI (char, 1, "", a + SR (0, 1), s); | |
309 | TI (char, 1, "", a + SR (0, DIFF_MAX - 1), s); | |
310 | TI (char, 2, "", a + SR (0, DIFF_MAX - 1), s); | |
311 | TI (char, 2, "", a + SR (1, DIFF_MAX - 1), s); | |
312 | /* The following is diagnosed not because the initial source offset | |
313 | it out of bounds (it isn't) but because the final source offset | |
314 | after the access has completed, is. It would be clearer if | |
315 | the warning mentioned the final offset. */ | |
6889a3ac | 316 | 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" } */ |
cc8bea0a MS |
317 | 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" } */ |
318 | ||
319 | TI (char, 3, "", a + SR (0, DIFF_MAX - 1), s); | |
320 | TI (char, 3, "", a + SR (1, DIFF_MAX - 1), s); | |
321 | TI (char, 3, "", a + SR (2, DIFF_MAX - 1), s); | |
6889a3ac | 322 | 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" } */ |
cc8bea0a MS |
323 | 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" } */ |
324 | ||
325 | 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" } */ | |
326 | } | |
327 | ||
328 | struct MA | |
329 | { | |
50e99db3 JL |
330 | #if __SIZEOF_INT__ == 2 |
331 | long i; | |
332 | #else | |
cc8bea0a | 333 | int i; |
50e99db3 | 334 | #endif |
cc8bea0a MS |
335 | char a5[5]; |
336 | char a11[11]; | |
337 | }; | |
338 | ||
339 | struct MA2 | |
340 | { | |
341 | struct MA ma3[3]; | |
342 | struct MA ma5[5]; | |
343 | char ax[]; | |
344 | }; | |
345 | ||
346 | struct MA3 | |
347 | { | |
348 | struct MA2 ma5[3]; | |
349 | struct MA2 ma7[7]; | |
350 | }; | |
351 | ||
352 | void test_strcpy_bounds_memarray_range (void) | |
353 | { | |
354 | #undef TM | |
355 | #define TM(mem, init, dst, src) \ | |
356 | do { \ | |
357 | struct MA ma; \ | |
358 | strcpy (ma.mem, init); \ | |
359 | strcpy (dst, src); \ | |
360 | sink (&ma); \ | |
361 | } while (0) | |
362 | ||
363 | ptrdiff_t i = SR (1, 2); | |
364 | ||
365 | TM (a5, "0", ma.a5 + i, ma.a5); | |
366 | TM (a5, "01", ma.a5 + i, ma.a5); | |
367 | TM (a5, "012", ma.a5 + i, ma.a5); | |
6889a3ac | 368 | 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" } */ |
cc8bea0a MS |
369 | |
370 | TM (a11, "0", ma.a5, ma.a11); | |
371 | TM (a11, "01", ma.a5, ma.a11); | |
372 | TM (a11, "012", ma.a5, ma.a11); | |
373 | TM (a11, "0123", ma.a5, ma.a11); | |
6889a3ac MS |
374 | 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" } */ |
375 | 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" } */ | |
376 | 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" } */ | |
cc8bea0a MS |
377 | |
378 | TM (a11, "0123456", ma.a11 + i, "789abcd"); | |
379 | } | |
380 | ||
381 | void test_strcpy_bounds_memarray_var (struct MA *pma, | |
382 | struct MA2 *pma2, | |
383 | struct MA3 *pma3, | |
384 | const char *s, size_t n) | |
385 | { | |
386 | #undef TM | |
387 | #define TM(dst, src) do { \ | |
388 | strcpy (dst, src); \ | |
389 | sink (dst, src); \ | |
390 | } while (0) | |
391 | ||
392 | TM (pma->a5, s); | |
393 | TM (pma->a5 + 0, s); | |
394 | TM (pma->a5 + 1, s); | |
395 | TM (pma->a5 + 4, s); | |
396 | ||
397 | /* The following forms a pointer during the call that's outside | |
398 | the bounds of the array it was derived from (pma->a5) so | |
399 | it should be diagnosed but the representation of the pointer | |
400 | addition doesn't contain information to distinguish it from | |
401 | the valid pma->a11 + 1 so this is an XFAIL. */ | |
402 | TM (pma->a5 + 5, s); /* { dg-warning "offset 17 from the object at .pma. is out of the bounds of .struct MA." "strcpy" { xfail *-*-* } } */ | |
403 | ||
404 | /* The following also forms an out-of-bounds pointer but similar | |
405 | to the above, there is no reliable way to distinguish it from | |
406 | (char*)&pma[1].i + 1 so this too is not diagnosed. */ | |
407 | 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 *-*-* } } */ | |
408 | ||
409 | TM (pma->a5 - 1, s); /* { dg-warning "offset -1 from the object at .pma. is out of the bounds of .struct MA." "strcpy" { xfail *-*-* } } */ | |
410 | ||
411 | TM (pma[1].a5, s); | |
412 | TM (pma[2].a5 + 0, s); | |
413 | TM (pma[3].a5 + 1, s); | |
414 | TM (pma[4].a5 + 4, s); | |
415 | ||
416 | ||
417 | extern struct MA3 ma3[3]; | |
418 | TM (ma3[0].ma5[0].ma3[0].a5 + 6, s); | |
419 | } |