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