1 /* Copyright (C) 2004, 2005  Free Software Foundation.
2 
3    Ensure builtin __strcpy_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 char *strcpy (char *, const char *);
10 extern int memcmp (const void *, const void *, size_t);
11 
12 #include "chk.h"
13 
14 LOCAL const char s1[] = "123";
15 char p[32] = "";
16 char *s2 = "defg";
17 char *s3 = "FGH";
18 char *s4;
19 size_t l1 = 1;
20 
21 void
22 __attribute__((noinline))
test1(void)23 test1 (void)
24 {
25   chk_calls = 0;
26 #ifndef __OPTIMIZE_SIZE__
27   strcpy_disallowed = 1;
28 #else
29   strcpy_disallowed = 0;
30 #endif
31 
32   if (strcpy (p, "abcde") != p || memcmp (p, "abcde", 6))
33     abort ();
34   if (strcpy (p + 16, "vwxyz" + 1) != p + 16 || memcmp (p + 16, "wxyz", 5))
35     abort ();
36   if (strcpy (p + 1, "") != p + 1 || memcmp (p, "a\0cde", 6))
37     abort ();
38   if (strcpy (p + 3, "fghij") != p + 3 || memcmp (p, "a\0cfghij", 9))
39     abort ();
40 
41   /* Test at least one instance of the __builtin_ style.  We do this
42      to ensure that it works and that the prototype is correct.  */
43   if (__builtin_strcpy (p, "abcde") != p || memcmp (p, "abcde", 6))
44     abort ();
45 
46   strcpy_disallowed = 0;
47   if (chk_calls)
48     abort ();
49 }
50 
51 #ifndef MAX_OFFSET
52 #define MAX_OFFSET (sizeof (long long))
53 #endif
54 
55 #ifndef MAX_COPY
56 #define MAX_COPY (10 * sizeof (long long))
57 #endif
58 
59 #ifndef MAX_EXTRA
60 #define MAX_EXTRA (sizeof (long long))
61 #endif
62 
63 #define MAX_LENGTH (MAX_OFFSET + MAX_COPY + 1 + MAX_EXTRA)
64 
65 /* Use a sequence length that is not divisible by two, to make it more
66    likely to detect when words are mixed up.  */
67 #define SEQUENCE_LENGTH 31
68 
69 static union {
70   char buf[MAX_LENGTH];
71   long long align_int;
72   long double align_fp;
73 } u1, u2;
74 
75 void
76 __attribute__((noinline))
test2(void)77 test2 (void)
78 {
79   int off1, off2, len, i;
80   char *p, *q, c;
81 
82   for (off1 = 0; off1 < MAX_OFFSET; off1++)
83     for (off2 = 0; off2 < MAX_OFFSET; off2++)
84       for (len = 1; len < MAX_COPY; len++)
85 	{
86 	  for (i = 0, c = 'A'; i < MAX_LENGTH; i++, c++)
87 	    {
88 	      u1.buf[i] = 'a';
89 	      if (c >= 'A' + SEQUENCE_LENGTH)
90 		c = 'A';
91 	      u2.buf[i] = c;
92 	    }
93 	  u2.buf[off2 + len] = '\0';
94 
95 	  p = strcpy (u1.buf + off1, u2.buf + off2);
96 	  if (p != u1.buf + off1)
97 	    abort ();
98 
99 	  q = u1.buf;
100 	  for (i = 0; i < off1; i++, q++)
101 	    if (*q != 'a')
102 	      abort ();
103 
104 	  for (i = 0, c = 'A' + off2; i < len; i++, q++, c++)
105 	    {
106 	      if (c >= 'A' + SEQUENCE_LENGTH)
107 		c = 'A';
108 	      if (*q != c)
109 		abort ();
110 	    }
111 
112 	  if (*q++ != '\0')
113 	    abort ();
114 	  for (i = 0; i < MAX_EXTRA; i++, q++)
115 	    if (*q != 'a')
116 	      abort ();
117 	}
118 }
119 
120 /* Test whether compile time checking is done where it should
121    and so is runtime object size checking.  */
122 void
123 __attribute__((noinline))
test3(void)124 test3 (void)
125 {
126   struct A { char buf1[10]; char buf2[10]; } a;
127   char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4];
128   char buf3[20];
129   int i;
130   const char *l;
131 
132   /* The following calls should do runtime checking
133      - source length is not known, but destination is.  */
134   chk_calls = 0;
135   strcpy (a.buf1 + 2, s3 + 3);
136   strcpy (r, s3 + 2);
137   r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
138   strcpy (r, s2 + 2);
139   strcpy (r + 2, s3 + 3);
140   r = buf3;
141   for (i = 0; i < 4; ++i)
142     {
143       if (i == l1 - 1)
144 	r = &a.buf1[1];
145       else if (i == l1)
146 	r = &a.buf2[7];
147       else if (i == l1 + 1)
148 	r = &buf3[5];
149       else if (i == l1 + 2)
150 	r = &a.buf1[9];
151     }
152   strcpy (r, s2 + 4);
153   if (chk_calls != 5)
154     abort ();
155 
156   /* Following have known destination and known source length,
157      so if optimizing certainly shouldn't result in the checking
158      variants.  */
159   chk_calls = 0;
160   strcpy (a.buf1 + 2, "");
161   strcpy (r, "a");
162   r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
163   strcpy (r, s1 + 1);
164   r = buf3;
165   l = "abc";
166   for (i = 0; i < 4; ++i)
167     {
168       if (i == l1 - 1)
169 	r = &a.buf1[1], l = "e";
170       else if (i == l1)
171 	r = &a.buf2[7], l = "gh";
172       else if (i == l1 + 1)
173 	r = &buf3[5], l = "jkl";
174       else if (i == l1 + 2)
175 	r = &a.buf1[9], l = "";
176     }
177   strcpy (r, "");
178   /* Here, strlen (l) + 1 is known to be at most 4 and
179      __builtin_object_size (&buf3[16], 0) is 4, so this doesn't need
180      runtime checking.  */
181   strcpy (&buf3[16], l);
182   /* Unknown destination and source, no checking.  */
183   strcpy (s4, s3);
184   if (chk_calls)
185     abort ();
186   chk_calls = 0;
187 }
188 
189 /* Test whether runtime and/or compile time checking catches
190    buffer overflows.  */
191 void
192 __attribute__((noinline))
test4(void)193 test4 (void)
194 {
195   struct A { char buf1[10]; char buf2[10]; } a;
196   char buf3[20];
197 
198   chk_fail_allowed = 1;
199   /* Runtime checks.  */
200   if (__builtin_setjmp (chk_fail_buf) == 0)
201     {
202       strcpy (&a.buf2[9], s2 + 3);
203       abort ();
204     }
205   if (__builtin_setjmp (chk_fail_buf) == 0)
206     {
207       strcpy (&a.buf2[7], s3 + strlen (s3) - 3);
208       abort ();
209     }
210   /* This should be detectable at compile time already.  */
211   if (__builtin_setjmp (chk_fail_buf) == 0)
212     {
213       strcpy (&buf3[19], "a");
214       abort ();
215     }
216   chk_fail_allowed = 0;
217 }
218 
219 void
main_test(void)220 main_test (void)
221 {
222 #ifndef __OPTIMIZE__
223   /* Object size checking is only intended for -O[s123].  */
224   return;
225 #endif
226   __asm ("" : "=r" (s2) : "0" (s2));
227   __asm ("" : "=r" (s3) : "0" (s3));
228   __asm ("" : "=r" (l1) : "0" (l1));
229   test1 ();
230   test2 ();
231   s4 = p;
232   test3 ();
233   test4 ();
234 }
235