1 /* Test for string function add boundaries of usable memory.
2 Copyright (C) 1996-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19 #define _GNU_SOURCE 1
20
21 /* Make sure we don't test the optimized inline functions if we want to
22 test the real implementation. */
23 #undef __USE_STRING_INLINES
24
25 #include <errno.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/mman.h>
30 #include <sys/param.h>
31
32 #ifndef CHAR
33 # define L(c) c
34 # define CHAR char
35 # define MEMSET memset
36 # define STRLEN strlen
37 # define STRNLEN strnlen
38 # define STRCHR strchr
39 # define STRRCHR strrchr
40 # define STRCPY strcpy
41 # define STRNCPY strncpy
42 # define MEMCMP memcmp
43 # define STPCPY stpcpy
44 # define STPNCPY stpncpy
45 # define MEMCPY memcpy
46 # define MEMPCPY mempcpy
47 # define MEMCHR memchr
48 # define STRCMP strcmp
49 # define STRNCMP strncmp
50 #endif
51
52
53 #define STRINGIFY(s) STRINGIFY2 (s)
54 #define STRINGIFY2(s) #s
55
56
57 int
do_test(void)58 do_test (void)
59 {
60 size_t size = sysconf (_SC_PAGESIZE);
61 size_t nchars = size / sizeof (CHAR);
62 CHAR *adr;
63 CHAR *dest;
64 int result = 0;
65
66 adr = (CHAR *) mmap (NULL, 3 * size, PROT_READ | PROT_WRITE,
67 MAP_PRIVATE | MAP_ANON, -1, 0);
68 dest = (CHAR *) mmap (NULL, 3 * size, PROT_READ | PROT_WRITE,
69 MAP_PRIVATE | MAP_ANON, -1, 0);
70 if (adr == MAP_FAILED || dest == MAP_FAILED)
71 {
72 if (errno == ENOSYS)
73 puts ("No test, mmap not available.");
74 else
75 {
76 printf ("mmap failed: %m");
77 result = 1;
78 }
79 }
80 else
81 {
82 size_t inner, middle, outer, nchars64, max128;
83
84 if (nchars > 64)
85 nchars64 = nchars - 64;
86 else
87 nchars64 = 0;
88
89 if (nchars > 128)
90 max128 = nchars - 128;
91 else
92 max128 = 0;
93
94 mprotect (adr, size, PROT_NONE);
95 mprotect (adr + 2 * nchars, size, PROT_NONE);
96 adr += nchars;
97
98 mprotect (dest, size, PROT_NONE);
99 mprotect (dest + 2 * nchars, size, PROT_NONE);
100 dest += nchars;
101
102 MEMSET (adr, L('T'), nchars);
103
104 /* strlen/wcslen test */
105 for (outer = nchars - 1; outer >= max128; --outer)
106 {
107 for (inner = MAX (outer, nchars64); inner < nchars; ++inner)
108 {
109 adr[inner] = L('\0');
110
111 if (STRLEN (&adr[outer]) != (size_t) (inner - outer))
112 {
113 printf ("%s flunked for outer = %zu, inner = %zu\n",
114 STRINGIFY (STRLEN), outer, inner);
115 result = 1;
116 }
117
118 adr[inner] = L('T');
119 }
120 if (outer == 0)
121 break;
122 }
123
124 /* strnlen/wcsnlen test */
125 for (outer = nchars; outer >= max128; --outer)
126 {
127 for (inner = MAX (outer, nchars64); inner < nchars; ++inner)
128 {
129 adr[inner] = L('\0');
130
131 if (STRNLEN (&adr[outer], inner - outer + 1)
132 != (size_t) (inner - outer))
133 {
134 printf ("%s flunked for outer = %zu, inner = %zu\n",
135 STRINGIFY (STRNLEN), outer, inner);
136 result = 1;
137 }
138
139 adr[inner] = L('T');
140 }
141 if (outer == 0)
142 break;
143 }
144 for (outer = nchars; outer >= max128; --outer)
145 {
146 for (inner = MAX (outer, nchars64); inner <= nchars; ++inner)
147 {
148 if (STRNLEN (&adr[outer], inner - outer)
149 != (size_t) (inner - outer))
150 {
151 printf ("%s flunked bounded for outer = %zu, inner = %zu\n",
152 STRINGIFY (STRNLEN), outer, inner);
153 result = 1;
154 }
155 }
156 if (outer == 0)
157 break;
158 }
159
160 /* strchr/wcschr test */
161 for (outer = nchars - 1; outer >= max128; --outer)
162 {
163 for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
164 {
165 for (inner = middle; inner < nchars; ++inner)
166 {
167 adr[middle] = L('V');
168 adr[inner] = L('\0');
169
170 CHAR *cp = STRCHR (&adr[outer], L('V'));
171
172 if ((inner == middle && cp != NULL)
173 || (inner != middle
174 && (cp - &adr[outer]) != middle - outer))
175 {
176 printf ("%s flunked for outer = %zu, middle = %zu, "
177 "inner = %zu\n",
178 STRINGIFY (STRCHR), outer, middle, inner);
179 result = 1;
180 }
181
182 adr[inner] = L('T');
183 adr[middle] = L('T');
184 }
185 }
186 if (outer == 0)
187 break;
188 }
189
190 /* Special test. */
191 adr[nchars - 1] = L('\0');
192 if (STRCHR (&adr[nchars - 1], L('\n')) != NULL)
193 {
194 printf ("%s flunked test of empty string at end of page\n",
195 STRINGIFY (STRCHR));
196 result = 1;
197 }
198
199 /* strrchr/wcsrchr test */
200 for (outer = nchars - 1; outer >= max128; --outer)
201 {
202 for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
203 {
204 for (inner = middle; inner < nchars; ++inner)
205 {
206 adr[middle] = L('V');
207 adr[inner] = L('\0');
208
209 CHAR *cp = STRRCHR (&adr[outer], L('V'));
210
211 if ((inner == middle && cp != NULL)
212 || (inner != middle
213 && (cp - &adr[outer]) != middle - outer))
214 {
215 printf ("%s flunked for outer = %zu, middle = %zu, "
216 "inner = %zu\n",
217 STRINGIFY (STRRCHR), outer, middle, inner);
218 result = 1;
219 }
220
221 adr[inner] = L('T');
222 adr[middle] = L('T');
223 }
224 }
225 if (outer == 0)
226 break;
227 }
228
229 /* memchr test */
230 for (outer = nchars - 1; outer >= max128; --outer)
231 {
232 for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
233 {
234 adr[middle] = L('V');
235
236 CHAR *cp = MEMCHR (&adr[outer], L('V'), 3 * size);
237
238 if (cp - &adr[outer] != middle - outer)
239 {
240 printf ("%s flunked for outer = %zu, middle = %zu\n",
241 STRINGIFY (MEMCHR), outer, middle);
242 result = 1;
243 }
244
245 adr[middle] = L('T');
246 }
247 if (outer == 0)
248 break;
249 }
250 for (outer = nchars; outer >= max128; --outer)
251 {
252 CHAR *cp = MEMCHR (&adr[outer], L('V'), nchars - outer);
253
254 if (cp != NULL)
255 {
256 printf ("%s flunked for outer = %zu\n",
257 STRINGIFY (MEMCHR), outer);
258 result = 1;
259 }
260 if (outer == 0)
261 break;
262 }
263
264 /* These functions only exist for single-byte characters. */
265 #ifndef WCSTEST
266 /* rawmemchr test */
267 for (outer = nchars - 1; outer >= max128; --outer)
268 {
269 for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
270 {
271 adr[middle] = L('V');
272
273 CHAR *cp = rawmemchr (&adr[outer], L('V'));
274
275 if (cp - &adr[outer] != middle - outer)
276 {
277 printf ("%s flunked for outer = %zu, middle = %zu\n",
278 STRINGIFY (rawmemchr), outer, middle);
279 result = 1;
280 }
281
282 adr[middle] = L('T');
283 }
284 if (outer == 0)
285 break;
286 }
287
288 /* memrchr test */
289 for (outer = nchars - 1; outer >= max128; --outer)
290 {
291 for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
292 {
293 adr[middle] = L('V');
294
295 CHAR *cp = memrchr (&adr[outer], L('V'), nchars - outer);
296
297 if (cp - &adr[outer] != middle - outer)
298 {
299 printf ("%s flunked for outer = %zu, middle = %zu\n",
300 STRINGIFY (memrchr), outer, middle);
301 result = 1;
302 }
303
304 adr[middle] = L('T');
305 }
306 if (outer == 0)
307 break;
308 }
309 for (outer = nchars; outer >= max128; --outer)
310 {
311 CHAR *cp = memrchr (&adr[outer], L('V'), nchars - outer);
312
313 if (cp != NULL)
314 {
315 printf ("%s flunked for outer = %zu\n",
316 STRINGIFY (memrchr), outer);
317 result = 1;
318 }
319 if (outer == 0)
320 break;
321 }
322 #endif
323
324 /* strcpy/wcscpy test */
325 for (outer = nchars - 1; outer >= max128; --outer)
326 {
327 for (inner = MAX (outer, nchars64); inner < nchars; ++inner)
328 {
329 adr[inner] = L('\0');
330
331 if (STRCPY (dest, &adr[outer]) != dest
332 || STRLEN (dest) != (size_t) (inner - outer))
333 {
334 printf ("%s flunked for outer = %zu, inner = %zu\n",
335 STRINGIFY (STRCPY), outer, inner);
336 result = 1;
337 }
338
339 adr[inner] = L('T');
340 }
341 if (outer == 0)
342 break;
343 }
344
345 /* strcmp/wcscmp tests */
346 for (outer = 1; outer < 32; ++outer)
347 for (middle = 0; middle < 16; ++middle)
348 {
349 MEMSET (adr + middle, L('T'), 256);
350 adr[256] = L('\0');
351 MEMSET (dest + nchars - outer, L('T'), outer - 1);
352 dest[nchars - 1] = L('\0');
353
354 if (STRCMP (adr + middle, dest + nchars - outer) <= 0)
355 {
356 printf ("%s 1 flunked for outer = %zu, middle = %zu\n",
357 STRINGIFY (STRCMP), outer, middle);
358 result = 1;
359 }
360
361 if (STRCMP (dest + nchars - outer, adr + middle) >= 0)
362 {
363 printf ("%s 2 flunked for outer = %zu, middle = %zu\n",
364 STRINGIFY (STRCMP), outer, middle);
365 result = 1;
366 }
367 }
368
369 /* strncmp/wcsncmp tests */
370 for (outer = 1; outer < 32; ++outer)
371 for (middle = 0; middle < 16; ++middle)
372 {
373 MEMSET (adr + middle, L('T'), 256);
374 adr[256] = L('\0');
375 MEMSET (dest + nchars - outer, L('T'), outer - 1);
376 dest[nchars - 1] = L('U');
377
378 for (inner = 0; inner < outer; ++inner)
379 {
380 if (STRNCMP (adr + middle, dest + nchars - outer, inner) != 0)
381 {
382 printf ("%s 1 flunked for outer = %zu, middle = %zu, "
383 "inner = %zu\n",
384 STRINGIFY (STRNCMP), outer, middle, inner);
385 result = 1;
386 }
387
388 if (STRNCMP (dest + nchars - outer, adr + middle, inner) != 0)
389 {
390 printf ("%s 2 flunked for outer = %zu, middle = %zu, "
391 "inner = %zu\n",
392 STRINGIFY (STRNCMP), outer, middle, inner);
393 result = 1;
394 }
395 }
396
397 if (STRNCMP (adr + middle, dest + nchars - outer, outer) >= 0)
398 {
399 printf ("%s 1 flunked for outer = %zu, middle = %zu, full\n",
400 STRINGIFY (STRNCMP), outer, middle);
401 result = 1;
402 }
403
404 if (STRNCMP (dest + nchars - outer, adr + middle, outer) <= 0)
405 {
406 printf ("%s 2 flunked for outer = %zu, middle = %zu, full\n",
407 STRINGIFY (STRNCMP), outer, middle);
408 result = 1;
409 }
410 }
411
412 /* strncpy/wcsncpy tests */
413 adr[nchars - 1] = L('T');
414 for (outer = nchars; outer >= max128; --outer)
415 {
416 size_t len;
417
418 for (len = 0; len < nchars - outer; ++len)
419 {
420 if (STRNCPY (dest, &adr[outer], len) != dest
421 || MEMCMP (dest, &adr[outer], len) != 0)
422 {
423 printf ("outer %s flunked for outer = %zu, len = %zu\n",
424 STRINGIFY (STRNCPY), outer, len);
425 result = 1;
426 }
427 }
428 if (outer == 0)
429 break;
430 }
431 adr[nchars - 1] = L('\0');
432
433 for (outer = nchars - 1; outer >= max128; --outer)
434 {
435 for (inner = MAX (outer, nchars64); inner < nchars; ++inner)
436 {
437 size_t len;
438
439 adr[inner] = L('\0');
440
441 for (len = 0; len < nchars - outer + 64; ++len)
442 {
443 if (STRNCPY (dest, &adr[outer], len) != dest
444 || MEMCMP (dest, &adr[outer],
445 MIN (inner - outer, len)) != 0
446 || (inner - outer < len
447 && STRLEN (dest) != (inner - outer)))
448 {
449 printf ("%s flunked for outer = %zu, inner = %zu, "
450 "len = %zu\n",
451 STRINGIFY (STRNCPY), outer, inner, len);
452 result = 1;
453 }
454 if (STRNCPY (dest + 1, &adr[outer], len) != dest + 1
455 || MEMCMP (dest + 1, &adr[outer],
456 MIN (inner - outer, len)) != 0
457 || (inner - outer < len
458 && STRLEN (dest + 1) != (inner - outer)))
459 {
460 printf ("%s+1 flunked for outer = %zu, inner = %zu, "
461 "len = %zu\n",
462 STRINGIFY (STRNCPY), outer, inner, len);
463 result = 1;
464 }
465 }
466
467 adr[inner] = L('T');
468 }
469 if (outer == 0)
470 break;
471 }
472
473 /* stpcpy/wcpcpy test */
474 for (outer = nchars - 1; outer >= max128; --outer)
475 {
476 for (inner = MAX (outer, nchars64); inner < nchars; ++inner)
477 {
478 adr[inner] = L('\0');
479
480 if ((STPCPY (dest, &adr[outer]) - dest) != inner - outer)
481 {
482 printf ("%s flunked for outer = %zu, inner = %zu\n",
483 STRINGIFY (STPCPY), outer, inner);
484 result = 1;
485 }
486
487 adr[inner] = L('T');
488 }
489 if (outer == 0)
490 break;
491 }
492
493 /* stpncpy/wcpncpy test */
494 adr[nchars - 1] = L('T');
495 for (outer = nchars; outer >= max128; --outer)
496 {
497 size_t len;
498
499 for (len = 0; len < nchars - outer; ++len)
500 {
501 if (STPNCPY (dest, &adr[outer], len) != dest + len
502 || MEMCMP (dest, &adr[outer], len) != 0)
503 {
504 printf ("outer %s flunked for outer = %zu, len = %zu\n",
505 STRINGIFY (STPNCPY), outer, len);
506 result = 1;
507 }
508 }
509 if (outer == 0)
510 break;
511 }
512 adr[nchars - 1] = L('\0');
513
514 for (outer = nchars - 1; outer >= max128; --outer)
515 {
516 for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
517 {
518 adr[middle] = L('\0');
519
520 for (inner = 0; inner < nchars - outer; ++ inner)
521 {
522 if ((STPNCPY (dest, &adr[outer], inner) - dest)
523 != MIN (inner, middle - outer))
524 {
525 printf ("%s flunked for outer = %zu, middle = %zu, "
526 "inner = %zu\n",
527 STRINGIFY (STPNCPY), outer, middle, inner);
528 result = 1;
529 }
530 }
531
532 adr[middle] = L('T');
533 }
534 if (outer == 0)
535 break;
536 }
537
538 /* memcpy/wmemcpy test */
539 for (outer = nchars; outer >= max128; --outer)
540 {
541 for (inner = 0; inner < nchars - outer; ++inner)
542 if (MEMCPY (dest, &adr[outer], inner) != dest)
543 {
544 printf ("%s flunked for outer = %zu, inner = %zu\n",
545 STRINGIFY (MEMCPY), outer, inner);
546 result = 1;
547 }
548 if (outer == 0)
549 break;
550 }
551
552 /* mempcpy/wmempcpy test */
553 for (outer = nchars; outer >= max128; --outer)
554 {
555 for (inner = 0; inner < nchars - outer; ++inner)
556 if (MEMPCPY (dest, &adr[outer], inner) != dest + inner)
557 {
558 printf ("%s flunked for outer = %zu, inner = %zu\n",
559 STRINGIFY (MEMPCPY), outer, inner);
560 result = 1;
561 }
562 if (outer == 0)
563 break;
564 }
565
566 /* This function only exists for single-byte characters. */
567 #ifndef WCSTEST
568 /* memccpy test */
569 memset (adr, '\0', nchars);
570 for (outer = nchars; outer >= max128; --outer)
571 {
572 for (inner = 0; inner < nchars - outer; ++inner)
573 if (memccpy (dest, &adr[outer], L('\1'), inner) != NULL)
574 {
575 printf ("memccpy flunked full copy for outer = %zu, inner = %zu\n",
576 outer, inner);
577 result = 1;
578 }
579 if (outer == 0)
580 break;
581 }
582 for (outer = nchars - 1; outer >= max128; --outer)
583 {
584 for (middle = 0; middle < nchars - outer; ++middle)
585 {
586 memset (dest, L('\2'), middle + 1);
587 for (inner = 0; inner < middle; ++inner)
588 {
589 adr[outer + inner] = L('\1');
590
591 if (memccpy (dest, &adr[outer], '\1', middle + 128)
592 != dest + inner + 1)
593 {
594 printf ("\
595 memccpy flunked partial copy for outer = %zu, middle = %zu, inner = %zu\n",
596 outer, middle, inner);
597 result = 1;
598 }
599 else if (dest[inner + 1] != L('\2'))
600 {
601 printf ("\
602 memccpy copied too much for outer = %zu, middle = %zu, inner = %zu\n",
603 outer, middle, inner);
604 result = 1;
605 }
606 adr[outer + inner] = L('\0');
607 }
608 }
609 if (outer == 0)
610 break;
611 }
612 #endif
613 }
614
615 return result;
616 }
617
618 #include <support/test-driver.c>
619