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