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