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