1 /* Test strncat functions.
2    Copyright (C) 2011-2022 Free Software Foundation, Inc.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #define TEST_MAIN
19 #ifndef WIDE
20 # define TEST_NAME "strncat"
21 #else
22 # define TEST_NAME "wcsncat"
23 #endif /* WIDE */
24 #include "test-string.h"
25 
26 #ifndef WIDE
27 # define STRNCAT strncat
28 # define CHAR char
29 # define UCHAR unsigned char
30 # define SIMPLE_STRNCAT simple_strncat
31 # define STRLEN strlen
32 # define MEMSET memset
33 # define MEMCPY memcpy
34 # define MEMCMP memcmp
35 # define BIG_CHAR CHAR_MAX
36 # define SMALL_CHAR 127
37 #else
38 # include <wchar.h>
39 # define STRNCAT wcsncat
40 # define CHAR wchar_t
41 # define UCHAR wchar_t
42 # define SIMPLE_STRNCAT simple_wcsncat
43 # define STRLEN wcslen
44 # define MEMSET wmemset
45 # define MEMCPY wmemcpy
46 # define MEMCMP wmemcmp
47 # define BIG_CHAR WCHAR_MAX
48 # define SMALL_CHAR 1273
49 #endif /* WIDE */
50 
51 typedef CHAR *(*proto_t) (CHAR *, const CHAR *, size_t);
52 
53 IMPL (STRNCAT, 2)
54 
55 /* Naive implementation to verify results.  */
56 CHAR *
SIMPLE_STRNCAT(CHAR * dst,const CHAR * src,size_t n)57 SIMPLE_STRNCAT (CHAR *dst, const CHAR *src, size_t n)
58 {
59   CHAR *ret = dst;
60   while (*dst++ != '\0');
61   --dst;
62   while (n--)
63     if ((*dst++ = *src++) == '\0')
64       return ret;
65   *dst = '\0';
66   return ret;
67 }
68 
69 static void
do_one_test(impl_t * impl,CHAR * dst,const CHAR * src,size_t n)70 do_one_test (impl_t *impl, CHAR *dst, const CHAR *src, size_t n)
71 {
72   size_t k = STRLEN (dst);
73   if (CALL (impl, dst, src, n) != dst)
74     {
75       error (0, 0, "Wrong result in function %s %p != %p", impl->name,
76 	     CALL (impl, dst, src, n), dst);
77       ret = 1;
78       return;
79     }
80 
81   size_t len = STRLEN (src);
82   if (MEMCMP (dst + k, src, len + 1 > n ? n : len + 1) != 0)
83     {
84       error (0, 0, "Incorrect concatenation in function %s",
85 	     impl->name);
86       ret = 1;
87       return;
88     }
89   if (n < len && dst[k + n] != '\0')
90     {
91       error (0, 0, "There is no zero in the end of output string in %s",
92 	     impl->name);
93       ret = 1;
94       return;
95     }
96 }
97 
98 static void
do_test(size_t align1,size_t align2,size_t len1,size_t len2,size_t n,int max_char)99 do_test (size_t align1, size_t align2, size_t len1, size_t len2,
100 	 size_t n, int max_char)
101 {
102   size_t i;
103   CHAR *s1, *s2;
104 
105   align1 &= 7;
106   if ((align1 + len1) * sizeof (CHAR) >= page_size)
107     return;
108   if ((align1 + n) * sizeof (CHAR) > page_size)
109     return;
110   align2 &= 7;
111   if ((align2 + len1 + len2) * sizeof (CHAR) >= page_size)
112     return;
113   if ((align2 + len1 + n) * sizeof (CHAR) > page_size)
114     return;
115   s1 = (CHAR *) (buf1) + align1;
116   s2 = (CHAR *) (buf2) + align2;
117 
118   for (i = 0; i < len1; ++i)
119     s1[i] = 32 + 23 * i % (max_char - 32);
120   s1[len1] = '\0';
121 
122   for (i = 0; i < len2; i++)
123     s2[i] = 32 + 23 * i % (max_char - 32);
124 
125   FOR_EACH_IMPL (impl, 0)
126     {
127       s2[len2] = '\0';
128       do_one_test (impl, s2, s1, n);
129     }
130 }
131 
132 static void
do_overflow_tests(void)133 do_overflow_tests (void)
134 {
135   size_t i, j, len;
136   const size_t one = 1;
137   CHAR *s1, *s2;
138   uintptr_t s1_addr;
139   s1 = (CHAR *) buf1;
140   s2 = (CHAR *) buf2;
141   s1_addr = (uintptr_t)s1;
142  for (j = 0; j < 200; ++j)
143       s2[j] = 32 + 23 * j % (BIG_CHAR - 32);
144  s2[200] = 0;
145   for (i = 0; i < 750; ++i) {
146     for (j = 0; j < i; ++j)
147       s1[j] = 32 + 23 * j % (BIG_CHAR - 32);
148     s1[i] = '\0';
149 
150        FOR_EACH_IMPL (impl, 0)
151     {
152       s2[200] = '\0';
153       do_one_test (impl, s2, s1, SIZE_MAX - i);
154       s2[200] = '\0';
155       do_one_test (impl, s2, s1, i - s1_addr);
156       s2[200] = '\0';
157       do_one_test (impl, s2, s1, -s1_addr - i);
158       s2[200] = '\0';
159       do_one_test (impl, s2, s1, SIZE_MAX - s1_addr - i);
160       s2[200] = '\0';
161       do_one_test (impl, s2, s1, SIZE_MAX - s1_addr + i);
162     }
163 
164     len = 0;
165     for (j = 8 * sizeof(size_t) - 1; j ; --j)
166       {
167         len |= one << j;
168         FOR_EACH_IMPL (impl, 0)
169           {
170             s2[200] = '\0';
171             do_one_test (impl, s2, s1, len - i);
172             s2[200] = '\0';
173             do_one_test (impl, s2, s1, len + i);
174             s2[200] = '\0';
175             do_one_test (impl, s2, s1, len - s1_addr - i);
176             s2[200] = '\0';
177             do_one_test (impl, s2, s1, len - s1_addr + i);
178 
179             s2[200] = '\0';
180             do_one_test (impl, s2, s1, ~len - i);
181             s2[200] = '\0';
182             do_one_test (impl, s2, s1, ~len + i);
183             s2[200] = '\0';
184             do_one_test (impl, s2, s1, ~len - s1_addr - i);
185             s2[200] = '\0';
186             do_one_test (impl, s2, s1, ~len - s1_addr + i);
187           }
188       }
189   }
190 }
191 
192 static void
do_random_tests(void)193 do_random_tests (void)
194 {
195   size_t i, j, n, align1, align2, len1, len2, N;
196   UCHAR *p1 = (UCHAR *) (buf1 + page_size) - 512;
197   UCHAR *p2 = (UCHAR *) (buf2 + page_size) - 512;
198   UCHAR *p3 = (UCHAR *) buf1;
199   UCHAR *res;
200   fprintf (stdout, "Number of iterations in random test = %zd\n",
201 	   ITERATIONS);
202   for (n = 0; n < ITERATIONS; n++)
203     {
204       N = random () & 255;
205       align1 = random () & 31;
206       if (random () & 1)
207 	align2 = random () & 31;
208       else
209 	align2 = align1 + (random () & 24);
210       len1 = random () & 511;
211       if (len1 + align2 > 512)
212 	len2 = random () & 7;
213       else
214 	len2 = (512 - len1 - align2) * (random () & (1024 * 1024 - 1))
215 	  / (1024 * 1024);
216       j = align1;
217       if (align2 + len2 > j)
218 	j = align2 + len2;
219       if (len1 + j >= 511)
220 	len1 = 510 - j - (random () & 7);
221       if (len1 >= 512)
222 	len1 = 0;
223       if (align1 + len1 < 512 - 8)
224 	{
225 	  j = 510 - align1 - len1 - (random () & 31);
226 	  if (j > 0 && j < 512)
227 	    align1 += j;
228 	}
229       j = len1 + align1 + 64;
230       if (j > 512)
231 	j = 512;
232       for (i = 0; i < j; i++)
233 	{
234 	  if (i == len1 + align1)
235 	    p1[i] = 0;
236 	  else
237 	    {
238 	      p1[i] = random () & BIG_CHAR;
239 	      if (i >= align1 && i < len1 + align1 && !p1[i])
240 		p1[i] = (random () & SMALL_CHAR) + 3;
241 	    }
242 	}
243       for (i = 0; i < len2; i++)
244 	{
245 	  p3[i] = random () & BIG_CHAR;
246 	  if (!p3[i])
247 	    p3[i] = (random () & SMALL_CHAR) + 3;
248 	}
249       p3[len2] = 0;
250 
251       FOR_EACH_IMPL (impl, 1)
252 	{
253 	  MEMSET (p2 - 64, '\1', align2 + 64);
254 	  MEMSET (p2 + align2 + len2 + 1, '\1', 512 - align2 - len2 - 1);
255 	  MEMCPY (p2 + align2, p3, len2 + 1);
256 	  res = (UCHAR *) CALL (impl, (CHAR *) (p2 + align2),
257 				(CHAR *) (p1 + align1), N);
258 	  if (res != p2 + align2)
259 	    {
260 	      error (0, 0, "Iteration %zd - wrong result in function %s "
261 		     "(%zd, %zd, %zd, %zd, %zd) %p != %p",
262 		     n, impl->name, align1, align2, len1, len2, N,
263 		     res, p2 + align2);
264 	      ret = 1;
265 	    }
266 	  for (j = 0; j < align2 + 64; ++j)
267 	    {
268 	      if (p2[j - 64] != '\1')
269 		{
270 		  error (0, 0, "Iteration %zd - garbage before dst, %s "
271 			 "%zd, %zd, %zd, %zd, %zd)",
272 			 n, impl->name, align1, align2, len1, len2, N);
273 		  ret = 1;
274 		  break;
275 		}
276 	    }
277 	  if (MEMCMP (p2 + align2, p3, len2))
278 	    {
279 	      error (0, 0, "Iteration %zd - garbage in string before, %s "
280 		     "(%zd, %zd, %zd, %zd, %zd)",
281 		     n, impl->name, align1, align2, len1, len2, N);
282 	      ret = 1;
283 	    }
284 
285 	  if ((len1 + 1) > N)
286 	    j = align2 + N + 1 + len2;
287 	  else
288 	    j = align2 + len1 + 1 + len2;
289 	  for (; j < 512; ++j)
290 	    {
291 	      if (p2[j] != '\1')
292 		{
293 		  error (0, 0, "Iteration %zd - garbage after, %s "
294 			 "(%zd, %zd, %zd, %zd, %zd)",
295 			 n, impl->name, align1, align2, len1, len2, N);
296 		  ret = 1;
297 		  break;
298 		}
299 	    }
300 	  if (len1 + 1 > N)
301 	    {
302 	      if (p2[align2 + N + len2] != '\0')
303 		{
304 		  error (0, 0, "Iteration %zd - there is no zero at the "
305 			 "end of output string, %s (%zd, %zd, %zd, %zd, %zd)",
306 			 n, impl->name, align1, align2, len1, len2, N);
307 		  ret = 1;
308 		}
309 	    }
310 	  if (MEMCMP (p1 + align1, p2 + align2 + len2,
311 		      (len1 + 1) > N ? N : len1 + 1))
312 	    {
313 	      error (0, 0, "Iteration %zd - different strings, %s "
314 		     "(%zd, %zd, %zd, %zd, %zd)",
315 		     n, impl->name, align1, align2, len1, len2, N);
316 	      ret = 1;
317 	    }
318 	}
319     }
320 }
321 
322 int
test_main(void)323 test_main (void)
324 {
325   size_t i, n;
326 
327   test_init ();
328 
329   printf ("%28s", "");
330   FOR_EACH_IMPL (impl, 0)
331     printf ("\t%s", impl->name);
332   putchar ('\n');
333 
334   for (n = 2; n <= 2048; n*=4)
335     {
336       do_test (0, 2, 2, 2, n, SMALL_CHAR);
337       do_test (0, 0, 4, 4, n, SMALL_CHAR);
338       do_test (4, 0, 4, 4, n, BIG_CHAR);
339       do_test (0, 0, 8, 8, n, SMALL_CHAR);
340       do_test (0, 8, 8, 8, n, SMALL_CHAR);
341 
342       do_test (0, 2, 2, 2, SIZE_MAX, SMALL_CHAR);
343       do_test (0, 0, 4, 4, SIZE_MAX, SMALL_CHAR);
344       do_test (4, 0, 4, 4, SIZE_MAX, BIG_CHAR);
345       do_test (0, 0, 8, 8, SIZE_MAX, SMALL_CHAR);
346       do_test (0, 8, 8, 8, SIZE_MAX, SMALL_CHAR);
347 
348       for (i = 1; i < 8; ++i)
349 	{
350 	  do_test (0, 0, 8 << i, 8 << i, n, SMALL_CHAR);
351 	  do_test (8 - i, 2 * i, 8 << i, 8 << i, n, SMALL_CHAR);
352 	  do_test (0, 0, 8 << i, 2 << i, n, SMALL_CHAR);
353 	  do_test (8 - i, 2 * i, 8 << i, 2 << i, n, SMALL_CHAR);
354 
355 	  do_test (0, 0, 8 << i, 8 << i, SIZE_MAX, SMALL_CHAR);
356 	  do_test (8 - i, 2 * i, 8 << i, 8 << i, SIZE_MAX, SMALL_CHAR);
357 	  do_test (0, 0, 8 << i, 2 << i, SIZE_MAX, SMALL_CHAR);
358 	  do_test (8 - i, 2 * i, 8 << i, 2 << i, SIZE_MAX, SMALL_CHAR);
359 	}
360 
361       for (i = 1; i < 8; ++i)
362 	{
363 	  do_test (i, 2 * i, 8 << i, 1, n, SMALL_CHAR);
364 	  do_test (2 * i, i, 8 << i, 1, n, BIG_CHAR);
365 	  do_test (i, i, 8 << i, 10, n, SMALL_CHAR);
366 
367 	  do_test (i, 2 * i, 8 << i, 1, SIZE_MAX, SMALL_CHAR);
368 	  do_test (2 * i, i, 8 << i, 1, SIZE_MAX, BIG_CHAR);
369 	  do_test (i, i, 8 << i, 10, SIZE_MAX, SMALL_CHAR);
370 	}
371     }
372 
373   do_random_tests ();
374   do_overflow_tests ();
375   return ret;
376 }
377 
378 #include <support/test-driver.c>
379