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