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