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