<string.h>: Make strchrnul, strcasestr, memmem available by default
[platform/upstream/glibc.git] / string / stratcliff.c
1 /* Test for string function add boundaries of usable memory.
2    Copyright (C) 1996-2023 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
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>