1 /* Exercise that -Warray-bounds is issued for out-of-bounds offsets
2 in calls to built-in functions.
4 { dg-options "-O2 -Wno-stringop-overflow -Warray-bounds -ftrack-macro-expansion=0" } */
6 #include "../gcc.dg/range.h"
9 # define restrict __restrict
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);
17 extern char* stpcpy (char* restrict
, const char* restrict
);
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);
27 void sink (void*, ...);
29 #define CAT(x, y) x ## y
30 #define CONCAT(x, y) CAT (x, y)
31 #define UNIQUE_NAME(x) CONCAT(x, __LINE__)
33 #define T(type, N, dst, src, n) do { \
34 extern type UNIQUE_NAME (a)[N]; \
35 type *a = UNIQUE_NAME (a); \
37 const type *ps = (src); \
43 void test_memcpy_bounds (char *d
, const char *s
, size_t n
)
47 /* Verify that invalid offsets into an array of known size are
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
);
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" } */
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" } */
66 /* Verify that invalid offsets into an array of unknown size are
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
);
82 /* Verify that all offsets via a pointer to an uknown object are
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
);
102 /* Verify offsets in an anti-range. */
104 void test_memcpy_bounds_anti_range (char *d
, const char *s
, size_t n
)
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 9 is out of the bounds \\\[0, 9] of object " "memcpy" } */
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
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 *-*-* } } */
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);
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" } */
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 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" } */
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);
150 /* Verify that pointer overflow in the computation done by memcpy
151 (i.e., offset + size) is detected and diagnosed. */
153 void test_memcpy_overflow (char *d
, const char *s
, size_t n
)
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 "\\\[-Warray-bounds" } */
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" } */
166 void test_memcpy_bounds_memarray_range (void)
169 #define TM(mem, dst, src, n) \
171 struct MA { char a5[5]; int i; } ma; \
172 sink (&ma); /* Initialize arrays. */ \
173 memcpy (dst, src, n); \
177 ptrdiff_t i
= SR (1, 2);
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); /* { dg-warning "\\\[-Warray-bounds" "pr101374" { xfail *-*-* } } */
182 TM (ma
.a5
, ma
.a5
+ i
, ma
.a5
, 7); /* diagnosed with -Warray-bounds=2 */
185 void test_memmove_bounds (char *d
, const char *s
, size_t n
)
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
);
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
);
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]." } */
207 void test_mempcpy_bounds (char *d
, const char *s
, size_t n
)
212 /* Verify that invalid offsets into an array of known size are
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
);
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" } */
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" } */
231 /* Verify that invalid offsets into an array of unknown size are
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
);
247 /* Verify that all offsets via a pointer to an uknown object are
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
);
267 #define TI(type, N, init, dst, src) do { \
268 type UNIQUE_NAME (a)[N] = init; \
269 type *a = UNIQUE_NAME (a); \
271 const type *ps = (src); \
273 sink (a, pd, ps, s); \
276 void test_strcpy_bounds (char *d
, const char *s
)
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 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]'" } */
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" } */
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));
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]'" } */
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" } */
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" } */
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. */
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" } */
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" } */
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
);
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" } */
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" } */
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" } */
330 #if __SIZEOF_INT__ == 2
352 void test_strcpy_bounds_memarray_range (void)
355 #define TM(mem, init, dst, src) \
358 strcpy (ma.mem, init); \
363 ptrdiff_t i
= SR (1, 2);
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
);
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" } */
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
);
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" } */
378 TM (a11
, "0123456", ma
.a11
+ i
, "789abcd");
381 void test_strcpy_bounds_memarray_var (struct MA
*pma
,
384 const char *s
, size_t n
)
387 #define TM(dst, src) do { \
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 *-*-* } } */
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 *-*-* } } */
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 *-*-* } } */
412 TM (pma
[2].a5
+ 0, s
);
413 TM (pma
[3].a5
+ 1, s
);
414 TM (pma
[4].a5
+ 4, s
);
417 extern struct MA3 ma3
[3];
418 TM (ma3
[0].ma5
[0].ma3
[0].a5
+ 6, s
);