1/* Copyright (C) 2004, 2005  Free Software Foundation.
2
3   Ensure builtin __strncat_chk performs correctly.  */
4
5extern void abort (void);
6typedef __SIZE_TYPE__ size_t;
7extern size_t strlen (const char *);
8extern void *memcpy (void *, const void *, size_t);
9extern char *strcat (char *, const char *);
10extern char *strncat (char *, const char *, size_t);
11extern int memcmp (const void *, const void *, size_t);
12extern char *strcpy (char *, const char *);
13extern int strcmp (const char *, const char *);
14extern void *memset (void *, int, size_t);
15
16#include "chk.h"
17
18const char s1[] = "123";
19char p[32] = "";
20char *s2 = "defg";
21char *s3 = "FGH";
22char *s4;
23size_t l1 = 1;
24char *s5;
25int x = 123;
26
27void
28__attribute__((noinline))
29test1 (void)
30{
31  const char *const s1 = "hello world";
32  const char *const s2 = "";
33  const char *s3;
34  char dst[64], *d2;
35
36  /* Following strncat calls should be all optimized out.  */
37  chk_calls = 0;
38  strncat_disallowed = 1;
39  strcat_disallowed = 1;
40  strcpy (dst, s1);
41  if (strncat (dst, "", 100) != dst || strcmp (dst, s1))
42    abort ();
43  strcpy (dst, s1);
44  if (strncat (dst, s2, 100) != dst || strcmp (dst, s1))
45    abort ();
46  strcpy (dst, s1); d2 = dst;
47  if (strncat (++d2, s2, 100) != dst+1 || d2 != dst+1 || strcmp (dst, s1))
48    abort ();
49  strcpy (dst, s1); d2 = dst;
50  if (strncat (++d2+5, s2, 100) != dst+6 || d2 != dst+1 || strcmp (dst, s1))
51    abort ();
52  strcpy (dst, s1); d2 = dst;
53  if (strncat (++d2+5, s1+11, 100) != dst+6 || d2 != dst+1 || strcmp (dst, s1))
54    abort ();
55  strcpy (dst, s1); d2 = dst;
56  if (strncat (++d2+5, s1, 0) != dst+6 || d2 != dst+1 || strcmp (dst, s1))
57    abort ();
58  strcpy (dst, s1); d2 = dst; s3 = s1;
59  if (strncat (++d2+5, ++s3, 0) != dst+6 || d2 != dst+1 || strcmp (dst, s1)
60      || s3 != s1 + 1)
61    abort ();
62  strcpy (dst, s1); d2 = dst;
63  if (strncat (++d2+5, "", ++x) != dst+6 || d2 != dst+1 || x != 124
64      || strcmp (dst, s1))
65    abort ();
66  if (chk_calls)
67    abort ();
68  strcat_disallowed = 0;
69
70  /* These __strncat_chk calls should be optimized into __strcat_chk,
71     as strlen (src) <= len.  */
72  strcpy (dst, s1);
73  if (strncat (dst, "foo", 3) != dst || strcmp (dst, "hello worldfoo"))
74    abort ();
75  strcpy (dst, s1);
76  if (strncat (dst, "foo", 100) != dst || strcmp (dst, "hello worldfoo"))
77    abort ();
78  strcpy (dst, s1);
79  if (strncat (dst, s1, 100) != dst || strcmp (dst, "hello worldhello world"))
80    abort ();
81  if (chk_calls != 3)
82    abort ();
83
84  chk_calls = 0;
85  /* The following calls have side-effects in dest, so are not checked.  */
86  strcpy (dst, s1); d2 = dst;
87  if (__builtin___strncat_chk (++d2, s1, 100, os (++d2)) != dst+1
88      || d2 != dst+1 || strcmp (dst, "hello worldhello world"))
89    abort ();
90  strcpy (dst, s1); d2 = dst;
91  if (__builtin___strncat_chk (++d2+5, s1, 100, os (++d2+5)) != dst+6
92      || d2 != dst+1 || strcmp (dst, "hello worldhello world"))
93    abort ();
94  strcpy (dst, s1); d2 = dst;
95  if (__builtin___strncat_chk (++d2+5, s1+5, 100, os (++d2+5)) != dst+6
96      || d2 != dst+1 || strcmp (dst, "hello world world"))
97    abort ();
98  if (chk_calls)
99    abort ();
100
101  chk_calls = 0;
102  strcat_disallowed = 1;
103
104  /* Test at least one instance of the __builtin_ style.  We do this
105     to ensure that it works and that the prototype is correct.  */
106  strcpy (dst, s1);
107  if (__builtin_strncat (dst, "", 100) != dst || strcmp (dst, s1))
108    abort ();
109
110  if (chk_calls)
111    abort ();
112  strncat_disallowed = 0;
113  strcat_disallowed = 0;
114}
115
116/* Test whether compile time checking is done where it should
117   and so is runtime object size checking.  */
118void
119__attribute__((noinline))
120test2 (void)
121{
122  struct A { char buf1[10]; char buf2[10]; } a;
123  char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4];
124  char buf3[20];
125  int i;
126
127  /* The following calls should do runtime checking.  */
128  memset (&a, '\0', sizeof (a));
129  s5 = (char *) &a;
130  __asm __volatile ("" : : "r" (s5) : "memory");
131  chk_calls = 0;
132  strncat (a.buf1 + 2, s3 + 3, l1 - 1);
133  strncat (r, s3 + 2, l1);
134  r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
135  memset (r, '\0', 3);
136  __asm __volatile ("" : : "r" (r) : "memory");
137  strncat (r, s2 + 2, l1 + 1);
138  strncat (r + 2, s3 + 3, l1 - 1);
139  r = buf3;
140  for (i = 0; i < 4; ++i)
141    {
142      if (i == l1 - 1)
143	r = &a.buf1[1];
144      else if (i == l1)
145	r = &a.buf2[7];
146      else if (i == l1 + 1)
147	r = &buf3[5];
148      else if (i == l1 + 2)
149	r = &a.buf1[9];
150    }
151  strncat (r, s2 + 4, l1);
152  if (chk_calls != 5)
153    abort ();
154
155  /* Following have known destination and known source length,
156     but we don't know the length of dest string, so runtime checking
157     is needed too.  */
158  memset (&a, '\0', sizeof (a));
159  chk_calls = 0;
160  s5 = (char *) &a;
161  __asm __volatile ("" : : "r" (s5) : "memory");
162  strncat (a.buf1 + 2, "a", 5);
163  strncat (r, "def", 0);
164  r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
165  memset (r, '\0', 3);
166  __asm __volatile ("" : : "r" (r) : "memory");
167  strncat (r, s1 + 1, 2);
168  if (chk_calls != 2)
169    abort ();
170  chk_calls = 0;
171  strcat_disallowed = 1;
172  /* Unknown destination and source, no checking.  */
173  strncat (s4, s3, l1 + 1);
174  strcat_disallowed = 0;
175  if (chk_calls)
176    abort ();
177}
178
179/* Test whether runtime and/or compile time checking catches
180   buffer overflows.  */
181void
182__attribute__((noinline))
183test3 (void)
184{
185  struct A { char buf1[10]; char buf2[10]; } a;
186  char buf3[20];
187
188  memset (&a, '\0', sizeof (a));
189  memset (buf3, '\0', sizeof (buf3));
190  s5 = (char *) &a;
191  __asm __volatile ("" : : "r" (s5) : "memory");
192  s5 = buf3;
193  __asm __volatile ("" : : "r" (s5) : "memory");
194  chk_fail_allowed = 1;
195  /* Runtime checks.  */
196  if (__builtin_setjmp (chk_fail_buf) == 0)
197    {
198      strncat (&a.buf2[9], s2 + 3, 4);
199      abort ();
200    }
201  if (__builtin_setjmp (chk_fail_buf) == 0)
202    {
203      strncat (&a.buf2[7], s3 + strlen (s3) - 3, 3);
204      abort ();
205    }
206  if (__builtin_setjmp (chk_fail_buf) == 0)
207    {
208      strncat (&buf3[19], "abcde", 1);
209      abort ();
210    }
211  chk_fail_allowed = 0;
212}
213
214void
215main_test (void)
216{
217#ifndef __OPTIMIZE__
218  /* Object size checking is only intended for -O[s123].  */
219  return;
220#endif
221  __asm ("" : "=r" (s2) : "0" (s2));
222  __asm ("" : "=r" (s3) : "0" (s3));
223  __asm ("" : "=r" (l1) : "0" (l1));
224  s4 = p;
225  test1 ();
226  memset (p, '\0', sizeof (p));
227  test2 ();
228  test3 ();
229}
230