1 /* Copyright (C) 2004, 2005  Free Software Foundation.
2 
3    Ensure builtin __vsprintf_chk performs correctly.  */
4 
5 #include <stdarg.h>
6 
7 extern void abort (void);
8 typedef __SIZE_TYPE__ size_t;
9 extern size_t strlen(const char *);
10 extern void *memcpy (void *, const void *, size_t);
11 extern char *strcpy (char *, const char *);
12 extern int memcmp (const void *, const void *, size_t);
13 extern void *memset (void *, int, size_t);
14 extern int vsprintf (char *, const char *, va_list);
15 
16 #include "chk.h"
17 
18 const char s1[] = "123";
19 char p[32] = "";
20 char *s2 = "defg";
21 char *s3 = "FGH";
22 char *s4;
23 size_t l1 = 1;
24 static char buffer[32];
25 char * volatile ptr = "barf";  /* prevent constant propagation to happen when whole program assumptions are made.  */
26 
27 int
28 __attribute__((noinline))
test1_sub(int i,...)29 test1_sub (int i, ...)
30 {
31   int ret = 0;
32   va_list ap;
33   va_start (ap, i);
34   switch (i)
35     {
36     case 0:
37       vsprintf (buffer, "foo", ap);
38       break;
39     case 1:
40       ret = vsprintf (buffer, "foo", ap);
41       break;
42     case 2:
43       vsprintf (buffer, "%s", ap);
44       break;
45     case 3:
46       ret = vsprintf (buffer, "%s", ap);
47       break;
48     case 4:
49       vsprintf (buffer, "%d - %c", ap);
50       break;
51     case 5:
52       vsprintf (s4, "%d - %c", ap);
53       break;
54     }
55   va_end (ap);
56   return ret;
57 }
58 
59 void
60 __attribute__((noinline))
test1(void)61 test1 (void)
62 {
63   chk_calls = 0;
64   vsprintf_disallowed = 1;
65 
66   memset (buffer, 'A', 32);
67   test1_sub (0);
68   if (memcmp (buffer, "foo", 4) || buffer[4] != 'A')
69     abort ();
70 
71   memset (buffer, 'A', 32);
72   if (test1_sub (1) != 3)
73     abort ();
74   if (memcmp (buffer, "foo", 4) || buffer[4] != 'A')
75     abort ();
76 
77   if (chk_calls)
78     abort ();
79   vsprintf_disallowed = 0;
80 
81   memset (buffer, 'A', 32);
82   test1_sub (2, "bar");
83   if (memcmp (buffer, "bar", 4) || buffer[4] != 'A')
84     abort ();
85 
86   memset (buffer, 'A', 32);
87   if (test1_sub (3, "bar") != 3)
88     abort ();
89   if (memcmp (buffer, "bar", 4) || buffer[4] != 'A')
90     abort ();
91 
92   memset (buffer, 'A', 32);
93   test1_sub (2, ptr);
94   if (memcmp (buffer, "barf", 5) || buffer[5] != 'A')
95     abort ();
96 
97   memset (buffer, 'A', 32);
98   test1_sub (4, (int) l1 + 27, *ptr);
99   if (memcmp (buffer, "28 - b\0AAAAA", 12))
100     abort ();
101 
102   if (chk_calls != 4)
103     abort ();
104   chk_calls = 0;
105 
106   test1_sub (5, (int) l1 - 17, ptr[1]);
107   if (memcmp (s4, "-16 - a", 8))
108     abort ();
109   if (chk_calls)
110     abort ();
111 }
112 
113 void
114 __attribute__((noinline))
test2_sub(int i,...)115 test2_sub (int i, ...)
116 {
117   va_list ap;
118   struct A { char buf1[10]; char buf2[10]; } a;
119   char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4];
120   char buf3[20];
121   int j;
122 
123   va_start (ap, i);
124   /* The following calls should do runtime checking
125      - source length is not known, but destination is.  */
126   switch (i)
127     {
128     case 0:
129       vsprintf (a.buf1 + 2, "%s", ap);
130       break;
131     case 1:
132       vsprintf (r, "%s%c", ap);
133       break;
134     case 2:
135       r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
136       vsprintf (r, "%c %s", ap);
137       break;
138     case 3:
139       r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
140       vsprintf (r + 2, s3 + 3, ap);
141       break;
142     case 4:
143     case 7:
144       r = buf3;
145       for (j = 0; j < 4; ++j)
146 	{
147 	  if (j == l1 - 1)
148 	    r = &a.buf1[1];
149 	  else if (j == l1)
150 	    r = &a.buf2[7];
151 	  else if (j == l1 + 1)
152 	    r = &buf3[5];
153 	  else if (j == l1 + 2)
154 	    r = &a.buf1[9];
155 	}
156       if (i == 4)
157 	vsprintf (r, s2 + 4, ap);
158       else
159 	vsprintf (r, "a", ap);
160       break;
161     case 5:
162       r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
163       vsprintf (r, "%s", ap);
164       break;
165     case 6:
166       vsprintf (a.buf1 + 2, "", ap);
167       break;
168     case 8:
169       vsprintf (s4, "%s %d", ap);
170       break;
171     }
172   va_end (ap);
173 }
174 
175 /* Test whether compile time checking is done where it should
176    and so is runtime object size checking.  */
177 void
178 __attribute__((noinline))
test2(void)179 test2 (void)
180 {
181   /* The following calls should do runtime checking
182      - source length is not known, but destination is.  */
183   chk_calls = 0;
184   test2_sub (0, s3 + 3);
185   test2_sub (1, s3 + 3, s3[3]);
186   test2_sub (2, s2[2], s2 + 4);
187   test2_sub (3);
188   test2_sub (4);
189   test2_sub (5, s1 + 1);
190   if (chk_calls != 6)
191     abort ();
192 
193   /* Following have known destination and known source length,
194      so if optimizing certainly shouldn't result in the checking
195      variants.  */
196   chk_calls = 0;
197   vsprintf_disallowed = 1;
198   test2_sub (6);
199   test2_sub (7);
200   vsprintf_disallowed = 0;
201   /* Unknown destination and source, no checking.  */
202   test2_sub (8, s3, 0);
203   if (chk_calls)
204     abort ();
205 }
206 
207 void
208 __attribute__((noinline))
test3_sub(int i,...)209 test3_sub (int i, ...)
210 {
211   va_list ap;
212   struct A { char buf1[10]; char buf2[10]; } a;
213   char buf3[20];
214 
215   va_start (ap, i);
216   /* The following calls should do runtime checking
217      - source length is not known, but destination is.  */
218   switch (i)
219     {
220     case 0:
221       vsprintf (&a.buf2[9], "%c%s", ap);
222       break;
223     case 1:
224       vsprintf (&a.buf2[7], "%s%c", ap);
225       break;
226     case 2:
227       vsprintf (&a.buf2[7], "%d", ap);
228       break;
229     case 3:
230       vsprintf (&buf3[17], "%s", ap);
231       break;
232     case 4:
233       vsprintf (&buf3[19], "a", ap);
234       break;
235     }
236   va_end (ap);
237 }
238 
239 /* Test whether runtime and/or compile time checking catches
240    buffer overflows.  */
241 void
242 __attribute__((noinline))
test3(void)243 test3 (void)
244 {
245   chk_fail_allowed = 1;
246   /* Runtime checks.  */
247   if (__builtin_setjmp (chk_fail_buf) == 0)
248     {
249       test3_sub (0, s2[3], s2 + 4);
250       abort ();
251     }
252   if (__builtin_setjmp (chk_fail_buf) == 0)
253     {
254       test3_sub (1, s3 + strlen (s3) - 2, *s3);
255       abort ();
256     }
257   if (__builtin_setjmp (chk_fail_buf) == 0)
258     {
259       test3_sub (2, (int) l1 + 9999);
260       abort ();
261     }
262   if (__builtin_setjmp (chk_fail_buf) == 0)
263     {
264       test3_sub (3, "abc");
265       abort ();
266     }
267   /* This should be detectable at compile time already.  */
268   if (__builtin_setjmp (chk_fail_buf) == 0)
269     {
270       test3_sub (4);
271       abort ();
272     }
273   chk_fail_allowed = 0;
274 }
275 
276 void
main_test(void)277 main_test (void)
278 {
279 #ifndef __OPTIMIZE__
280   /* Object size checking is only intended for -O[s123].  */
281   return;
282 #endif
283   __asm ("" : "=r" (s2) : "0" (s2));
284   __asm ("" : "=r" (s3) : "0" (s3));
285   __asm ("" : "=r" (l1) : "0" (l1));
286   s4 = p;
287   test1 ();
288   test2 ();
289   test3 ();
290 }
291