1#include <stdarg.h>
2#ifdef __unix__
3#include <sys/types.h>
4#endif
5
6extern void abort (void);
7
8extern int inside_main;
9void *chk_fail_buf[256] __attribute__((aligned (16)));
10volatile int chk_fail_allowed, chk_calls;
11volatile int memcpy_disallowed, mempcpy_disallowed, memmove_disallowed;
12volatile int memset_disallowed, strcpy_disallowed, stpcpy_disallowed;
13volatile int strncpy_disallowed, strcat_disallowed, strncat_disallowed;
14volatile int sprintf_disallowed, vsprintf_disallowed;
15volatile int snprintf_disallowed, vsnprintf_disallowed;
16extern __SIZE_TYPE__ strlen (const char *);
17extern int vsprintf (char *, const char *, va_list);
18
19void __attribute__((noreturn))
20__chk_fail (void)
21{
22  if (chk_fail_allowed)
23    __builtin_longjmp (chk_fail_buf, 1);
24  abort ();
25}
26
27void *
28memcpy (void *dst, const void *src, __SIZE_TYPE__ n)
29{
30  const char *srcp;
31  char *dstp;
32
33#ifdef __OPTIMIZE__
34  if (memcpy_disallowed && inside_main)
35    abort ();
36#endif
37
38  srcp = src;
39  dstp = dst;
40  while (n-- != 0)
41    *dstp++ = *srcp++;
42
43  return dst;
44}
45
46void *
47__memcpy_chk (void *dst, const void *src, __SIZE_TYPE__ n, __SIZE_TYPE__ size)
48{
49  /* If size is -1, GCC should always optimize the call into memcpy.  */
50  if (size == (__SIZE_TYPE__) -1)
51    abort ();
52  ++chk_calls;
53  if (n > size)
54    __chk_fail ();
55  return memcpy (dst, src, n);
56}
57
58void *
59mempcpy (void *dst, const void *src, __SIZE_TYPE__ n)
60{
61  const char *srcp;
62  char *dstp;
63
64#ifdef __OPTIMIZE__
65  if (mempcpy_disallowed && inside_main)
66    abort ();
67#endif
68
69  srcp = src;
70  dstp = dst;
71  while (n-- != 0)
72    *dstp++ = *srcp++;
73
74  return dstp;
75}
76
77void *
78__mempcpy_chk (void *dst, const void *src, __SIZE_TYPE__ n, __SIZE_TYPE__ size)
79{
80  /* If size is -1, GCC should always optimize the call into mempcpy.  */
81  if (size == (__SIZE_TYPE__) -1)
82    abort ();
83  ++chk_calls;
84  if (n > size)
85    __chk_fail ();
86  return mempcpy (dst, src, n);
87}
88
89void *
90memmove (void *dst, const void *src, __SIZE_TYPE__ n)
91{
92  const char *srcp;
93  char *dstp;
94
95#ifdef __OPTIMIZE__
96  if (memmove_disallowed && inside_main)
97    abort ();
98#endif
99
100  srcp = src;
101  dstp = dst;
102  if (srcp < dstp)
103    while (n-- != 0)
104      dstp[n] = srcp[n];
105  else
106    while (n-- != 0)
107      *dstp++ = *srcp++;
108
109  return dst;
110}
111
112void *
113__memmove_chk (void *dst, const void *src, __SIZE_TYPE__ n, __SIZE_TYPE__ size)
114{
115  /* If size is -1, GCC should always optimize the call into memmove.  */
116  if (size == (__SIZE_TYPE__) -1)
117    abort ();
118  ++chk_calls;
119  if (n > size)
120    __chk_fail ();
121  return memmove (dst, src, n);
122}
123
124void *
125memset (void *dst, int c, __SIZE_TYPE__ n)
126{
127  /* Single-byte memsets should be done inline when optimisation
128     is enabled.  */
129#ifdef __OPTIMIZE__
130  if (memset_disallowed && inside_main && n < 2)
131    abort ();
132#endif
133
134  while (n-- != 0)
135    n[(char *) dst] = c;
136
137  return dst;
138}
139
140void *
141__memset_chk (void *dst, int c, __SIZE_TYPE__ n, __SIZE_TYPE__ size)
142{
143  /* If size is -1, GCC should always optimize the call into memset.  */
144  if (size == (__SIZE_TYPE__) -1)
145    abort ();
146  ++chk_calls;
147  if (n > size)
148    __chk_fail ();
149  return memset (dst, c, n);
150}
151
152char *
153strcpy (char *d, const char *s)
154{
155  char *r = d;
156#ifdef __OPTIMIZE__
157  if (strcpy_disallowed && inside_main)
158    abort ();
159#endif
160  while ((*d++ = *s++));
161  return r;
162}
163
164char *
165__strcpy_chk (char *d, const char *s, __SIZE_TYPE__ size)
166{
167  /* If size is -1, GCC should always optimize the call into strcpy.  */
168  if (size == (__SIZE_TYPE__) -1)
169    abort ();
170  ++chk_calls;
171  if (strlen (s) >= size)
172    __chk_fail ();
173  return strcpy (d, s);
174}
175
176char *
177stpcpy (char *dst, const char *src)
178{
179#ifdef __OPTIMIZE__
180  if (stpcpy_disallowed && inside_main)
181    abort ();
182#endif
183
184  while (*src != 0)
185    *dst++ = *src++;
186
187  *dst = 0;
188  return dst;
189}
190
191char *
192__stpcpy_chk (char *d, const char *s, __SIZE_TYPE__ size)
193{
194  /* If size is -1, GCC should always optimize the call into stpcpy.  */
195  if (size == (__SIZE_TYPE__) -1)
196    abort ();
197  ++chk_calls;
198  if (strlen (s) >= size)
199    __chk_fail ();
200  return stpcpy (d, s);
201}
202
203char *
204strncpy (char *s1, const char *s2, __SIZE_TYPE__ n)
205{
206  char *dest = s1;
207#ifdef __OPTIMIZE__
208  if (strncpy_disallowed && inside_main)
209    abort();
210#endif
211  for (; *s2 && n; n--)
212    *s1++ = *s2++;
213  while (n--)
214    *s1++ = 0;
215  return dest;
216}
217
218char *
219__strncpy_chk (char *s1, const char *s2, __SIZE_TYPE__ n, __SIZE_TYPE__ size)
220{
221  /* If size is -1, GCC should always optimize the call into strncpy.  */
222  if (size == (__SIZE_TYPE__) -1)
223    abort ();
224  ++chk_calls;
225  if (n > size)
226    __chk_fail ();
227  return strncpy (s1, s2, n);
228}
229
230char *
231strcat (char *dst, const char *src)
232{
233  char *p = dst;
234
235#ifdef __OPTIMIZE__
236  if (strcat_disallowed && inside_main)
237    abort ();
238#endif
239
240  while (*p)
241    p++;
242  while ((*p++ = *src++))
243    ;
244  return dst;
245}
246
247char *
248__strcat_chk (char *d, const char *s, __SIZE_TYPE__ size)
249{
250  /* If size is -1, GCC should always optimize the call into strcat.  */
251  if (size == (__SIZE_TYPE__) -1)
252    abort ();
253  ++chk_calls;
254  if (strlen (d) + strlen (s) >= size)
255    __chk_fail ();
256  return strcat (d, s);
257}
258
259char *
260strncat (char *s1, const char *s2, __SIZE_TYPE__ n)
261{
262  char *dest = s1;
263  char c;
264#ifdef __OPTIMIZE__
265  if (strncat_disallowed && inside_main)
266    abort();
267#endif
268  while (*s1) s1++;
269  c = '\0';
270  while (n > 0)
271    {
272      c = *s2++;
273      *s1++ = c;
274      if (c == '\0')
275	return dest;
276      n--;
277    }
278  if (c != '\0')
279    *s1 = '\0';
280  return dest;
281}
282
283char *
284__strncat_chk (char *d, const char *s, __SIZE_TYPE__ n, __SIZE_TYPE__ size)
285{
286  __SIZE_TYPE__ len = strlen (d), n1 = n;
287  const char *s1 = s;
288
289  /* If size is -1, GCC should always optimize the call into strncat.  */
290  if (size == (__SIZE_TYPE__) -1)
291    abort ();
292  ++chk_calls;
293  while (len < size && n1 > 0)
294    {
295      if (*s1++ == '\0')
296	break;
297      ++len;
298      --n1;
299    }
300
301  if (len >= size)
302    __chk_fail ();
303  return strncat (d, s, n);
304}
305
306/* No chk test in GCC testsuite needs more bytes than this.
307   As we can't expect vsnprintf to be available on the target,
308   assume 4096 bytes is enough.  */
309static char chk_sprintf_buf[4096];
310
311int
312__sprintf_chk (char *str, int flag, __SIZE_TYPE__ size, const char *fmt, ...)
313{
314  int ret;
315  va_list ap;
316
317  /* If size is -1 and flag 0, GCC should always optimize the call into
318     sprintf.  */
319  if (size == (__SIZE_TYPE__) -1 && flag == 0)
320    abort ();
321  ++chk_calls;
322#ifdef __OPTIMIZE__
323  if (sprintf_disallowed && inside_main)
324    abort();
325#endif
326  va_start (ap, fmt);
327  ret = vsprintf (chk_sprintf_buf, fmt, ap);
328  va_end (ap);
329  if (ret >= 0)
330    {
331      if (ret >= size)
332	__chk_fail ();
333      memcpy (str, chk_sprintf_buf, ret + 1);
334    }
335  return ret;
336}
337
338int
339__vsprintf_chk (char *str, int flag, __SIZE_TYPE__ size, const char *fmt,
340		va_list ap)
341{
342  int ret;
343
344  /* If size is -1 and flag 0, GCC should always optimize the call into
345     vsprintf.  */
346  if (size == (__SIZE_TYPE__) -1 && flag == 0)
347    abort ();
348  ++chk_calls;
349#ifdef __OPTIMIZE__
350  if (vsprintf_disallowed && inside_main)
351    abort();
352#endif
353  ret = vsprintf (chk_sprintf_buf, fmt, ap);
354  if (ret >= 0)
355    {
356      if (ret >= size)
357	__chk_fail ();
358      memcpy (str, chk_sprintf_buf, ret + 1);
359    }
360  return ret;
361}
362
363int
364__snprintf_chk (char *str, __SIZE_TYPE__ len, int flag, __SIZE_TYPE__ size,
365		const char *fmt, ...)
366{
367  int ret;
368  va_list ap;
369
370  /* If size is -1 and flag 0, GCC should always optimize the call into
371     snprintf.  */
372  if (size == (__SIZE_TYPE__) -1 && flag == 0)
373    abort ();
374  ++chk_calls;
375  if (size < len)
376    __chk_fail ();
377#ifdef __OPTIMIZE__
378  if (snprintf_disallowed && inside_main)
379    abort();
380#endif
381  va_start (ap, fmt);
382  ret = vsprintf (chk_sprintf_buf, fmt, ap);
383  va_end (ap);
384  if (ret >= 0)
385    {
386      if (ret < len)
387	memcpy (str, chk_sprintf_buf, ret + 1);
388      else
389	{
390	  memcpy (str, chk_sprintf_buf, len - 1);
391	  str[len - 1] = '\0';
392	}
393    }
394  return ret;
395}
396
397int
398__vsnprintf_chk (char *str, __SIZE_TYPE__ len, int flag, __SIZE_TYPE__ size,
399		 const char *fmt, va_list ap)
400{
401  int ret;
402
403  /* If size is -1 and flag 0, GCC should always optimize the call into
404     vsnprintf.  */
405  if (size == (__SIZE_TYPE__) -1 && flag == 0)
406    abort ();
407  ++chk_calls;
408  if (size < len)
409    __chk_fail ();
410#ifdef __OPTIMIZE__
411  if (vsnprintf_disallowed && inside_main)
412    abort();
413#endif
414  ret = vsprintf (chk_sprintf_buf, fmt, ap);
415  if (ret >= 0)
416    {
417      if (ret < len)
418	memcpy (str, chk_sprintf_buf, ret + 1);
419      else
420	{
421	  memcpy (str, chk_sprintf_buf, len - 1);
422	  str[len - 1] = '\0';
423	}
424    }
425  return ret;
426}
427
428int
429snprintf (char *str, __SIZE_TYPE__ len, const char *fmt, ...)
430{
431  int ret;
432  va_list ap;
433
434#ifdef __OPTIMIZE__
435  if (snprintf_disallowed && inside_main)
436    abort();
437#endif
438  va_start (ap, fmt);
439  ret = vsprintf (chk_sprintf_buf, fmt, ap);
440  va_end (ap);
441  if (ret >= 0)
442    {
443      if (ret < len)
444	memcpy (str, chk_sprintf_buf, ret + 1);
445      else if (len)
446	{
447	  memcpy (str, chk_sprintf_buf, len - 1);
448	  str[len - 1] = '\0';
449	}
450    }
451  return ret;
452}
453
454/* uClibc's vsprintf calls vsnprintf.  */
455#ifndef __UCLIBC__
456int
457vsnprintf (char *str, __SIZE_TYPE__ len, const char *fmt, va_list ap)
458{
459  int ret;
460
461#ifdef __OPTIMIZE__
462  if (vsnprintf_disallowed && inside_main)
463    abort();
464#endif
465  ret = vsprintf (chk_sprintf_buf, fmt, ap);
466  if (ret >= 0)
467    {
468      if (ret < len)
469	memcpy (str, chk_sprintf_buf, ret + 1);
470      else if (len)
471	{
472	  memcpy (str, chk_sprintf_buf, len - 1);
473	  str[len - 1] = '\0';
474	}
475    }
476  return ret;
477}
478#endif
479