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