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