1 /* Copyright (C) 2004, 2005 Free Software Foundation.
2
3 Ensure builtin __memcpy_chk performs correctly. */
4
5 extern void abort (void);
6 typedef __SIZE_TYPE__ size_t;
7 extern size_t strlen(const char *);
8 extern void *memcpy (void *, const void *, size_t);
9 extern int memcmp (const void *, const void *, size_t);
10
11 #include "chk.h"
12
13 const char s1[] = "123";
14 char p[32] = "";
15 volatile char *s2 = "defg"; /* prevent constant propagation to happen when whole program assumptions are made. */
16 volatile char *s3 = "FGH"; /* prevent constant propagation to happen when whole program assumptions are made. */
17 volatile size_t l1 = 1; /* prevent constant propagation to happen when whole program assumptions are made. */
18
19 void
20 __attribute__((noinline))
test1(void)21 test1 (void)
22 {
23 int i;
24
25 #if defined __i386__ || defined __x86_64__
26 /* The functions below might not be optimized into direct stores on all
27 arches. It depends on how many instructions would be generated and
28 what limits the architecture chooses in STORE_BY_PIECES_P. */
29 memcpy_disallowed = 1;
30 #endif
31
32 /* All the memcpy calls in this routine except last have fixed length, so
33 object size checking should be done at compile time if optimizing. */
34 chk_calls = 0;
35
36 if (memcpy (p, "ABCDE", 6) != p || memcmp (p, "ABCDE", 6))
37 abort ();
38 if (memcpy (p + 16, "VWX" + 1, 2) != p + 16
39 || memcmp (p + 16, "WX\0\0", 5))
40 abort ();
41 if (memcpy (p + 1, "", 1) != p + 1 || memcmp (p, "A\0CDE", 6))
42 abort ();
43 if (memcpy (p + 3, "FGHI", 4) != p + 3 || memcmp (p, "A\0CFGHI", 8))
44 abort ();
45
46 i = 8;
47 memcpy (p + 20, "qrstu", 6);
48 memcpy (p + 25, "QRSTU", 6);
49 if (memcpy (p + 25 + 1, s1, 3) != p + 25 + 1
50 || memcmp (p + 25, "Q123U", 6))
51 abort ();
52
53 if (memcpy (memcpy (p, "abcdEFG", 4) + 4, "efg", 4) != p + 4
54 || memcmp (p, "abcdefg", 8))
55 abort();
56
57 /* Test at least one instance of the __builtin_ style. We do this
58 to ensure that it works and that the prototype is correct. */
59 if (__builtin_memcpy (p, "ABCDE", 6) != p || memcmp (p, "ABCDE", 6))
60 abort ();
61
62 memcpy (p + 5, s3, 1);
63 if (memcmp (p, "ABCDEFg", 8))
64 abort ();
65
66 memcpy_disallowed = 0;
67 if (chk_calls)
68 abort ();
69 chk_calls = 0;
70
71 memcpy (p + 6, s1 + 1, l1);
72 if (memcmp (p, "ABCDEF2", 8))
73 abort ();
74
75 /* The above memcpy copies into an object with known size, but
76 unknown length, so it should be a __memcpy_chk call. */
77 if (chk_calls != 1)
78 abort ();
79 }
80
81 long buf1[64];
82 char *buf2 = (char *) (buf1 + 32);
83 long buf5[20];
84 char buf7[20];
85
86 void
87 __attribute__((noinline))
test2_sub(long * buf3,char * buf4,char * buf6,int n)88 test2_sub (long *buf3, char *buf4, char *buf6, int n)
89 {
90 int i = 0;
91
92 /* All the memcpy/__builtin_memcpy/__builtin___memcpy_chk
93 calls in this routine are either fixed length, or have
94 side-effects in __builtin_object_size arguments, or
95 dst doesn't point into a known object. */
96 chk_calls = 0;
97
98 /* These should probably be handled by store_by_pieces on most arches. */
99 if (memcpy (buf1, "ABCDEFGHI", 9) != (char *) buf1
100 || memcmp (buf1, "ABCDEFGHI\0", 11))
101 abort ();
102
103 if (memcpy (buf1, "abcdefghijklmnopq", 17) != (char *) buf1
104 || memcmp (buf1, "abcdefghijklmnopq\0", 19))
105 abort ();
106
107 if (__builtin_memcpy (buf3, "ABCDEF", 6) != (char *) buf1
108 || memcmp (buf1, "ABCDEFghijklmnopq\0", 19))
109 abort ();
110
111 if (__builtin_memcpy (buf3, "a", 1) != (char *) buf1
112 || memcmp (buf1, "aBCDEFghijklmnopq\0", 19))
113 abort ();
114
115 if (memcpy ((char *) buf3 + 2, "bcd" + ++i, 2) != (char *) buf1 + 2
116 || memcmp (buf1, "aBcdEFghijklmnopq\0", 19)
117 || i != 1)
118 abort ();
119
120 /* These should probably be handled by move_by_pieces on most arches. */
121 if (memcpy ((char *) buf3 + 4, buf5, 6) != (char *) buf1 + 4
122 || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19))
123 abort ();
124
125 if (__builtin_memcpy ((char *) buf1 + ++i + 8, (char *) buf5 + 1, 1)
126 != (char *) buf1 + 10
127 || memcmp (buf1, "aBcdRSTUVWSlmnopq\0", 19)
128 || i != 2)
129 abort ();
130
131 if (memcpy ((char *) buf3 + 14, buf6, 2) != (char *) buf1 + 14
132 || memcmp (buf1, "aBcdRSTUVWSlmnrsq\0", 19))
133 abort ();
134
135 if (memcpy (buf3, buf5, 8) != (char *) buf1
136 || memcmp (buf1, "RSTUVWXYVWSlmnrsq\0", 19))
137 abort ();
138
139 if (memcpy (buf3, buf5, 17) != (char *) buf1
140 || memcmp (buf1, "RSTUVWXYZ01234567\0", 19))
141 abort ();
142
143 __builtin_memcpy (buf3, "aBcdEFghijklmnopq\0", 19);
144
145 /* These should be handled either by movmemendM or memcpy
146 call. */
147
148 /* buf3 points to an unknown object, so __memcpy_chk should not be done. */
149 if (memcpy ((char *) buf3 + 4, buf5, n + 6) != (char *) buf1 + 4
150 || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19))
151 abort ();
152
153 /* This call has side-effects in dst, therefore no checking. */
154 if (__builtin___memcpy_chk ((char *) buf1 + ++i + 8, (char *) buf5 + 1,
155 n + 1, os ((char *) buf1 + ++i + 8))
156 != (char *) buf1 + 11
157 || memcmp (buf1, "aBcdRSTUVWkSmnopq\0", 19)
158 || i != 3)
159 abort ();
160
161 if (memcpy ((char *) buf3 + 14, buf6, n + 2) != (char *) buf1 + 14
162 || memcmp (buf1, "aBcdRSTUVWkSmnrsq\0", 19))
163 abort ();
164
165 i = 1;
166
167 /* These might be handled by store_by_pieces. */
168 if (memcpy (buf2, "ABCDEFGHI", 9) != buf2
169 || memcmp (buf2, "ABCDEFGHI\0", 11))
170 abort ();
171
172 if (memcpy (buf2, "abcdefghijklmnopq", 17) != buf2
173 || memcmp (buf2, "abcdefghijklmnopq\0", 19))
174 abort ();
175
176 if (__builtin_memcpy (buf4, "ABCDEF", 6) != buf2
177 || memcmp (buf2, "ABCDEFghijklmnopq\0", 19))
178 abort ();
179
180 if (__builtin_memcpy (buf4, "a", 1) != buf2
181 || memcmp (buf2, "aBCDEFghijklmnopq\0", 19))
182 abort ();
183
184 if (memcpy (buf4 + 2, "bcd" + i++, 2) != buf2 + 2
185 || memcmp (buf2, "aBcdEFghijklmnopq\0", 19)
186 || i != 2)
187 abort ();
188
189 /* These might be handled by move_by_pieces. */
190 if (memcpy (buf4 + 4, buf7, 6) != buf2 + 4
191 || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19))
192 abort ();
193
194 /* Side effect. */
195 if (__builtin___memcpy_chk (buf2 + i++ + 8, buf7 + 1, 1,
196 os (buf2 + i++ + 8))
197 != buf2 + 10
198 || memcmp (buf2, "aBcdRSTUVWSlmnopq\0", 19)
199 || i != 3)
200 abort ();
201
202 if (memcpy (buf4 + 14, buf6, 2) != buf2 + 14
203 || memcmp (buf2, "aBcdRSTUVWSlmnrsq\0", 19))
204 abort ();
205
206 __builtin_memcpy (buf4, "aBcdEFghijklmnopq\0", 19);
207
208 /* These should be handled either by movmemendM or memcpy
209 call. */
210 if (memcpy (buf4 + 4, buf7, n + 6) != buf2 + 4
211 || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19))
212 abort ();
213
214 /* Side effect. */
215 if (__builtin___memcpy_chk (buf2 + i++ + 8, buf7 + 1, n + 1,
216 os (buf2 + i++ + 8))
217 != buf2 + 11
218 || memcmp (buf2, "aBcdRSTUVWkSmnopq\0", 19)
219 || i != 4)
220 abort ();
221
222 if (memcpy (buf4 + 14, buf6, n + 2) != buf2 + 14
223 || memcmp (buf2, "aBcdRSTUVWkSmnrsq\0", 19))
224 abort ();
225
226 if (chk_calls)
227 abort ();
228 }
229
230 void
231 __attribute__((noinline))
test2(void)232 test2 (void)
233 {
234 long *x;
235 char *y;
236 int z;
237 __builtin_memcpy (buf5, "RSTUVWXYZ0123456789", 20);
238 __builtin_memcpy (buf7, "RSTUVWXYZ0123456789", 20);
239 __asm ("" : "=r" (x) : "0" (buf1));
240 __asm ("" : "=r" (y) : "0" (buf2));
241 __asm ("" : "=r" (z) : "0" (0));
242 test2_sub (x, y, "rstuvwxyz", z);
243 }
244
245 /* Test whether compile time checking is done where it should
246 and so is runtime object size checking. */
247 void
248 __attribute__((noinline))
test3(void)249 test3 (void)
250 {
251 struct A { char buf1[10]; char buf2[10]; } a;
252 char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4];
253 char buf3[20];
254 int i;
255 size_t l;
256
257 /* The following calls should do runtime checking
258 - length is not known, but destination is. */
259 chk_calls = 0;
260 memcpy (a.buf1 + 2, s3, l1);
261 memcpy (r, s3, l1 + 1);
262 r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
263 memcpy (r, s2, l1 + 2);
264 memcpy (r + 2, s3, l1);
265 r = buf3;
266 for (i = 0; i < 4; ++i)
267 {
268 if (i == l1 - 1)
269 r = &a.buf1[1];
270 else if (i == l1)
271 r = &a.buf2[7];
272 else if (i == l1 + 1)
273 r = &buf3[5];
274 else if (i == l1 + 2)
275 r = &a.buf1[9];
276 }
277 memcpy (r, s2, l1);
278 if (chk_calls != 5)
279 abort ();
280
281 /* Following have known destination and known length,
282 so if optimizing certainly shouldn't result in the checking
283 variants. */
284 chk_calls = 0;
285 memcpy (a.buf1 + 2, s3, 1);
286 memcpy (r, s3, 2);
287 r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
288 memcpy (r, s2, 3);
289 r = buf3;
290 l = 4;
291 for (i = 0; i < 4; ++i)
292 {
293 if (i == l1 - 1)
294 r = &a.buf1[1], l = 2;
295 else if (i == l1)
296 r = &a.buf2[7], l = 3;
297 else if (i == l1 + 1)
298 r = &buf3[5], l = 4;
299 else if (i == l1 + 2)
300 r = &a.buf1[9], l = 1;
301 }
302 memcpy (r, s2, 1);
303 /* Here, l is known to be at most 4 and __builtin_object_size (&buf3[16], 0)
304 is 4, so this doesn't need runtime checking. */
305 memcpy (&buf3[16], s2, l);
306 if (chk_calls)
307 abort ();
308 chk_calls = 0;
309 }
310
311 /* Test whether runtime and/or compile time checking catches
312 buffer overflows. */
313 void
314 __attribute__((noinline))
test4(void)315 test4 (void)
316 {
317 struct A { char buf1[10]; char buf2[10]; } a;
318 char buf3[20];
319
320 chk_fail_allowed = 1;
321 /* Runtime checks. */
322 if (__builtin_setjmp (chk_fail_buf) == 0)
323 {
324 memcpy (&a.buf2[9], s2, l1 + 1);
325 abort ();
326 }
327 if (__builtin_setjmp (chk_fail_buf) == 0)
328 {
329 memcpy (&a.buf2[7], s3, strlen (s3) + 1);
330 abort ();
331 }
332 /* This should be detectable at compile time already. */
333 if (__builtin_setjmp (chk_fail_buf) == 0)
334 {
335 memcpy (&buf3[19], "ab", 2);
336 abort ();
337 }
338 chk_fail_allowed = 0;
339 }
340
341 #ifndef MAX_OFFSET
342 #define MAX_OFFSET (sizeof (long long))
343 #endif
344
345 #ifndef MAX_COPY
346 #define MAX_COPY (10 * sizeof (long long))
347 #endif
348
349 #ifndef MAX_EXTRA
350 #define MAX_EXTRA (sizeof (long long))
351 #endif
352
353 #define MAX_LENGTH (MAX_OFFSET + MAX_COPY + MAX_EXTRA)
354
355 /* Use a sequence length that is not divisible by two, to make it more
356 likely to detect when words are mixed up. */
357 #define SEQUENCE_LENGTH 31
358
359 static union {
360 char buf[MAX_LENGTH];
361 long long align_int;
362 long double align_fp;
363 } u1, u2;
364
365 void
366 __attribute__((noinline))
test5(void)367 test5 (void)
368 {
369 int off1, off2, len, i;
370 char *p, *q, c;
371
372 for (off1 = 0; off1 < MAX_OFFSET; off1++)
373 for (off2 = 0; off2 < MAX_OFFSET; off2++)
374 for (len = 1; len < MAX_COPY; len++)
375 {
376 for (i = 0, c = 'A'; i < MAX_LENGTH; i++, c++)
377 {
378 u1.buf[i] = 'a';
379 if (c >= 'A' + SEQUENCE_LENGTH)
380 c = 'A';
381 u2.buf[i] = c;
382 }
383
384 p = memcpy (u1.buf + off1, u2.buf + off2, len);
385 if (p != u1.buf + off1)
386 abort ();
387
388 q = u1.buf;
389 for (i = 0; i < off1; i++, q++)
390 if (*q != 'a')
391 abort ();
392
393 for (i = 0, c = 'A' + off2; i < len; i++, q++, c++)
394 {
395 if (c >= 'A' + SEQUENCE_LENGTH)
396 c = 'A';
397 if (*q != c)
398 abort ();
399 }
400
401 for (i = 0; i < MAX_EXTRA; i++, q++)
402 if (*q != 'a')
403 abort ();
404 }
405 }
406
407 #define TESTSIZE 80
408
409 char srcb[TESTSIZE] __attribute__ ((aligned));
410 char dstb[TESTSIZE] __attribute__ ((aligned));
411
412 void
413 __attribute__((noinline))
check(char * test,char * match,int n)414 check (char *test, char *match, int n)
415 {
416 if (memcmp (test, match, n))
417 abort ();
418 }
419
420 #define TN(n) \
421 { memset (dstb, 0, n); memcpy (dstb, srcb, n); check (dstb, srcb, n); }
422 #define T(n) \
423 TN (n) \
424 TN ((n) + 1) \
425 TN ((n) + 2) \
426 TN ((n) + 3)
427
428 void
429 __attribute__((noinline))
test6(void)430 test6 (void)
431 {
432 int i;
433
434 chk_calls = 0;
435
436 for (i = 0; i < sizeof (srcb); ++i)
437 srcb[i] = 'a' + i % 26;
438
439 T (0);
440 T (4);
441 T (8);
442 T (12);
443 T (16);
444 T (20);
445 T (24);
446 T (28);
447 T (32);
448 T (36);
449 T (40);
450 T (44);
451 T (48);
452 T (52);
453 T (56);
454 T (60);
455 T (64);
456 T (68);
457 T (72);
458 T (76);
459
460 /* All memcpy calls in this routine have constant arguments. */
461 if (chk_calls)
462 abort ();
463 }
464
465 void
main_test(void)466 main_test (void)
467 {
468 #ifndef __OPTIMIZE__
469 /* Object size checking is only intended for -O[s123]. */
470 return;
471 #endif
472 __asm ("" : "=r" (l1) : "0" (l1));
473 test1 ();
474 test2 ();
475 test3 ();
476 test4 ();
477 test5 ();
478 test6 ();
479 }
480