| /* Test for string function add boundaries of usable memory. |
| Copyright (C) 1996-2014 Free Software Foundation, Inc. |
| This file is part of the GNU C Library. |
| Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. |
| |
| The GNU C Library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Lesser General Public |
| License as published by the Free Software Foundation; either |
| version 2.1 of the License, or (at your option) any later version. |
| |
| The GNU C Library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public |
| License along with the GNU C Library; if not, see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #define _GNU_SOURCE 1 |
| |
| /* Make sure we don't test the optimized inline functions if we want to |
| test the real implementation. */ |
| #undef __USE_STRING_INLINES |
| |
| #include <errno.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <sys/mman.h> |
| #include <sys/param.h> |
| |
| #ifndef CHAR |
| # define L(c) c |
| # define CHAR char |
| # define MEMSET memset |
| # define STRLEN strlen |
| # define STRNLEN strnlen |
| # define STRCHR strchr |
| # define STRRCHR strrchr |
| # define STRCPY strcpy |
| # define STRNCPY strncpy |
| # define MEMCMP memcmp |
| # define STPCPY stpcpy |
| # define STPNCPY stpncpy |
| # define MEMCPY memcpy |
| # define MEMPCPY mempcpy |
| # define MEMCHR memchr |
| # define STRCMP strcmp |
| # define STRNCMP strncmp |
| #endif |
| |
| |
| #define STRINGIFY(s) STRINGIFY2 (s) |
| #define STRINGIFY2(s) #s |
| |
| |
| static int |
| do_test (void) |
| { |
| int size = sysconf (_SC_PAGESIZE); |
| int nchars = size / sizeof (CHAR); |
| CHAR *adr; |
| CHAR *dest; |
| int result = 0; |
| |
| adr = (CHAR *) mmap (NULL, 3 * size, PROT_READ | PROT_WRITE, |
| MAP_PRIVATE | MAP_ANON, -1, 0); |
| dest = (CHAR *) mmap (NULL, 3 * size, PROT_READ | PROT_WRITE, |
| MAP_PRIVATE | MAP_ANON, -1, 0); |
| if (adr == MAP_FAILED || dest == MAP_FAILED) |
| { |
| if (errno == ENOSYS) |
| puts ("No test, mmap not available."); |
| else |
| { |
| printf ("mmap failed: %m"); |
| result = 1; |
| } |
| } |
| else |
| { |
| int inner, middle, outer; |
| |
| mprotect (adr, size, PROT_NONE); |
| mprotect (adr + 2 * nchars, size, PROT_NONE); |
| adr += nchars; |
| |
| mprotect (dest, size, PROT_NONE); |
| mprotect (dest + 2 * nchars, size, PROT_NONE); |
| dest += nchars; |
| |
| MEMSET (adr, L('T'), nchars); |
| |
| /* strlen/wcslen test */ |
| for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) |
| { |
| for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) |
| { |
| adr[inner] = L('\0'); |
| |
| if (STRLEN (&adr[outer]) != (size_t) (inner - outer)) |
| { |
| printf ("%s flunked for outer = %d, inner = %d\n", |
| STRINGIFY (STRLEN), outer, inner); |
| result = 1; |
| } |
| |
| adr[inner] = L('T'); |
| } |
| } |
| |
| /* strnlen/wcsnlen test */ |
| for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) |
| { |
| for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) |
| { |
| adr[inner] = L('\0'); |
| |
| if (STRNLEN (&adr[outer], inner - outer + 1) |
| != (size_t) (inner - outer)) |
| { |
| printf ("%s flunked for outer = %d, inner = %d\n", |
| STRINGIFY (STRNLEN), outer, inner); |
| result = 1; |
| } |
| |
| adr[inner] = L('T'); |
| } |
| } |
| for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) |
| { |
| for (inner = MAX (outer, nchars - 64); inner <= nchars; ++inner) |
| { |
| if (STRNLEN (&adr[outer], inner - outer) |
| != (size_t) (inner - outer)) |
| { |
| printf ("%s flunked bounded for outer = %d, inner = %d\n", |
| STRINGIFY (STRNLEN), outer, inner); |
| result = 1; |
| } |
| } |
| } |
| |
| /* strchr/wcschr test */ |
| for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) |
| { |
| for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) |
| { |
| for (inner = middle; inner < nchars; ++inner) |
| { |
| adr[middle] = L('V'); |
| adr[inner] = L('\0'); |
| |
| CHAR *cp = STRCHR (&adr[outer], L('V')); |
| |
| if ((inner == middle && cp != NULL) |
| || (inner != middle |
| && (cp - &adr[outer]) != middle - outer)) |
| { |
| printf ("%s flunked for outer = %d, middle = %d, " |
| "inner = %d\n", |
| STRINGIFY (STRCHR), outer, middle, inner); |
| result = 1; |
| } |
| |
| adr[inner] = L('T'); |
| adr[middle] = L('T'); |
| } |
| } |
| } |
| |
| /* Special test. */ |
| adr[nchars - 1] = L('\0'); |
| if (STRCHR (&adr[nchars - 1], L('\n')) != NULL) |
| { |
| printf ("%s flunked test of empty string at end of page\n", |
| STRINGIFY (STRCHR)); |
| result = 1; |
| } |
| |
| /* strrchr/wcsrchr test */ |
| for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) |
| { |
| for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) |
| { |
| for (inner = middle; inner < nchars; ++inner) |
| { |
| adr[middle] = L('V'); |
| adr[inner] = L('\0'); |
| |
| CHAR *cp = STRRCHR (&adr[outer], L('V')); |
| |
| if ((inner == middle && cp != NULL) |
| || (inner != middle |
| && (cp - &adr[outer]) != middle - outer)) |
| { |
| printf ("%s flunked for outer = %d, middle = %d, " |
| "inner = %d\n", |
| STRINGIFY (STRRCHR), outer, middle, inner); |
| result = 1; |
| } |
| |
| adr[inner] = L('T'); |
| adr[middle] = L('T'); |
| } |
| } |
| } |
| |
| /* memchr test */ |
| for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) |
| { |
| for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) |
| { |
| adr[middle] = L('V'); |
| |
| CHAR *cp = MEMCHR (&adr[outer], L('V'), 3 * size); |
| |
| if (cp - &adr[outer] != middle - outer) |
| { |
| printf ("%s flunked for outer = %d, middle = %d\n", |
| STRINGIFY (MEMCHR), outer, middle); |
| result = 1; |
| } |
| |
| adr[middle] = L('T'); |
| } |
| } |
| for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) |
| { |
| CHAR *cp = MEMCHR (&adr[outer], L('V'), nchars - outer); |
| |
| if (cp != NULL) |
| { |
| printf ("%s flunked for outer = %d\n", |
| STRINGIFY (MEMCHR), outer); |
| result = 1; |
| } |
| } |
| |
| /* These functions only exist for single-byte characters. */ |
| #ifndef WCSTEST |
| /* rawmemchr test */ |
| for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) |
| { |
| for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) |
| { |
| adr[middle] = L('V'); |
| |
| CHAR *cp = rawmemchr (&adr[outer], L('V')); |
| |
| if (cp - &adr[outer] != middle - outer) |
| { |
| printf ("%s flunked for outer = %d, middle = %d\n", |
| STRINGIFY (rawmemchr), outer, middle); |
| result = 1; |
| } |
| |
| adr[middle] = L('T'); |
| } |
| } |
| |
| /* memrchr test */ |
| for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) |
| { |
| for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) |
| { |
| adr[middle] = L('V'); |
| |
| CHAR *cp = memrchr (&adr[outer], L('V'), nchars - outer); |
| |
| if (cp - &adr[outer] != middle - outer) |
| { |
| printf ("%s flunked for outer = %d, middle = %d\n", |
| STRINGIFY (memrchr), outer, middle); |
| result = 1; |
| } |
| |
| adr[middle] = L('T'); |
| } |
| } |
| for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) |
| { |
| CHAR *cp = memrchr (&adr[outer], L('V'), nchars - outer); |
| |
| if (cp != NULL) |
| { |
| printf ("%s flunked for outer = %d\n", |
| STRINGIFY (memrchr), outer); |
| result = 1; |
| } |
| } |
| #endif |
| |
| /* strcpy/wcscpy test */ |
| for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) |
| { |
| for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) |
| { |
| adr[inner] = L('\0'); |
| |
| if (STRCPY (dest, &adr[outer]) != dest |
| || STRLEN (dest) != (size_t) (inner - outer)) |
| { |
| printf ("%s flunked for outer = %d, inner = %d\n", |
| STRINGIFY (STRCPY), outer, inner); |
| result = 1; |
| } |
| |
| adr[inner] = L('T'); |
| } |
| } |
| |
| /* strcmp/wcscmp tests */ |
| for (outer = 1; outer < 32; ++outer) |
| for (middle = 0; middle < 16; ++middle) |
| { |
| MEMSET (adr + middle, L('T'), 256); |
| adr[256] = L('\0'); |
| MEMSET (dest + nchars - outer, L('T'), outer - 1); |
| dest[nchars - 1] = L('\0'); |
| |
| if (STRCMP (adr + middle, dest + nchars - outer) <= 0) |
| { |
| printf ("%s 1 flunked for outer = %d, middle = %d\n", |
| STRINGIFY (STRCMP), outer, middle); |
| result = 1; |
| } |
| |
| if (STRCMP (dest + nchars - outer, adr + middle) >= 0) |
| { |
| printf ("%s 2 flunked for outer = %d, middle = %d\n", |
| STRINGIFY (STRCMP), outer, middle); |
| result = 1; |
| } |
| } |
| |
| /* strncmp/wcsncmp tests */ |
| for (outer = 1; outer < 32; ++outer) |
| for (middle = 0; middle < 16; ++middle) |
| { |
| MEMSET (adr + middle, L('T'), 256); |
| adr[256] = L('\0'); |
| MEMSET (dest + nchars - outer, L('T'), outer - 1); |
| dest[nchars - 1] = L('U'); |
| |
| for (inner = 0; inner < outer; ++inner) |
| { |
| if (STRNCMP (adr + middle, dest + nchars - outer, inner) != 0) |
| { |
| printf ("%s 1 flunked for outer = %d, middle = %d, " |
| "inner = %d\n", |
| STRINGIFY (STRNCMP), outer, middle, inner); |
| result = 1; |
| } |
| |
| if (STRNCMP (dest + nchars - outer, adr + middle, inner) != 0) |
| { |
| printf ("%s 2 flunked for outer = %d, middle = %d, " |
| "inner = %d\n", |
| STRINGIFY (STRNCMP), outer, middle, inner); |
| result = 1; |
| } |
| } |
| |
| if (STRNCMP (adr + middle, dest + nchars - outer, outer) >= 0) |
| { |
| printf ("%s 1 flunked for outer = %d, middle = %d, full\n", |
| STRINGIFY (STRNCMP), outer, middle); |
| result = 1; |
| } |
| |
| if (STRNCMP (dest + nchars - outer, adr + middle, outer) <= 0) |
| { |
| printf ("%s 2 flunked for outer = %d, middle = %d, full\n", |
| STRINGIFY (STRNCMP), outer, middle); |
| result = 1; |
| } |
| } |
| |
| /* strncpy/wcsncpy tests */ |
| adr[nchars - 1] = L('T'); |
| for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) |
| { |
| size_t len; |
| |
| for (len = 0; len < nchars - outer; ++len) |
| { |
| if (STRNCPY (dest, &adr[outer], len) != dest |
| || MEMCMP (dest, &adr[outer], len) != 0) |
| { |
| printf ("outer %s flunked for outer = %d, len = %Zd\n", |
| STRINGIFY (STRNCPY), outer, len); |
| result = 1; |
| } |
| } |
| } |
| adr[nchars - 1] = L('\0'); |
| |
| for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) |
| { |
| for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) |
| { |
| size_t len; |
| |
| adr[inner] = L('\0'); |
| |
| for (len = 0; len < nchars - outer + 64; ++len) |
| { |
| if (STRNCPY (dest, &adr[outer], len) != dest |
| || MEMCMP (dest, &adr[outer], |
| MIN (inner - outer, len)) != 0 |
| || (inner - outer < len |
| && STRLEN (dest) != (inner - outer))) |
| { |
| printf ("%s flunked for outer = %d, inner = %d, " |
| "len = %Zd\n", |
| STRINGIFY (STRNCPY), outer, inner, len); |
| result = 1; |
| } |
| if (STRNCPY (dest + 1, &adr[outer], len) != dest + 1 |
| || MEMCMP (dest + 1, &adr[outer], |
| MIN (inner - outer, len)) != 0 |
| || (inner - outer < len |
| && STRLEN (dest + 1) != (inner - outer))) |
| { |
| printf ("%s+1 flunked for outer = %d, inner = %d, " |
| "len = %Zd\n", |
| STRINGIFY (STRNCPY), outer, inner, len); |
| result = 1; |
| } |
| } |
| |
| adr[inner] = L('T'); |
| } |
| } |
| |
| /* stpcpy/wcpcpy test */ |
| for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) |
| { |
| for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) |
| { |
| adr[inner] = L('\0'); |
| |
| if ((STPCPY (dest, &adr[outer]) - dest) != inner - outer) |
| { |
| printf ("%s flunked for outer = %d, inner = %d\n", |
| STRINGIFY (STPCPY), outer, inner); |
| result = 1; |
| } |
| |
| adr[inner] = L('T'); |
| } |
| } |
| |
| /* stpncpy/wcpncpy test */ |
| adr[nchars - 1] = L('T'); |
| for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) |
| { |
| size_t len; |
| |
| for (len = 0; len < nchars - outer; ++len) |
| { |
| if (STPNCPY (dest, &adr[outer], len) != dest + len |
| || MEMCMP (dest, &adr[outer], len) != 0) |
| { |
| printf ("outer %s flunked for outer = %d, len = %Zd\n", |
| STRINGIFY (STPNCPY), outer, len); |
| result = 1; |
| } |
| } |
| } |
| adr[nchars - 1] = L('\0'); |
| |
| for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) |
| { |
| for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) |
| { |
| adr[middle] = L('\0'); |
| |
| for (inner = 0; inner < nchars - outer; ++ inner) |
| { |
| if ((STPNCPY (dest, &adr[outer], inner) - dest) |
| != MIN (inner, middle - outer)) |
| { |
| printf ("%s flunked for outer = %d, middle = %d, " |
| "inner = %d\n", |
| STRINGIFY (STPNCPY), outer, middle, inner); |
| result = 1; |
| } |
| } |
| |
| adr[middle] = L('T'); |
| } |
| } |
| |
| /* memcpy/wmemcpy test */ |
| for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) |
| for (inner = 0; inner < nchars - outer; ++inner) |
| if (MEMCPY (dest, &adr[outer], inner) != dest) |
| { |
| printf ("%s flunked for outer = %d, inner = %d\n", |
| STRINGIFY (MEMCPY), outer, inner); |
| result = 1; |
| } |
| |
| /* mempcpy/wmempcpy test */ |
| for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) |
| for (inner = 0; inner < nchars - outer; ++inner) |
| if (MEMPCPY (dest, &adr[outer], inner) != dest + inner) |
| { |
| printf ("%s flunked for outer = %d, inner = %d\n", |
| STRINGIFY (MEMPCPY), outer, inner); |
| result = 1; |
| } |
| |
| /* This function only exists for single-byte characters. */ |
| #ifndef WCSTEST |
| /* memccpy test */ |
| memset (adr, '\0', nchars); |
| for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) |
| for (inner = 0; inner < nchars - outer; ++inner) |
| if (memccpy (dest, &adr[outer], L('\1'), inner) != NULL) |
| { |
| printf ("memccpy flunked full copy for outer = %d, inner = %d\n", |
| outer, inner); |
| result = 1; |
| } |
| for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) |
| for (middle = 0; middle < nchars - outer; ++middle) |
| { |
| memset (dest, L('\2'), middle + 1); |
| for (inner = 0; inner < middle; ++inner) |
| { |
| adr[outer + inner] = L('\1'); |
| |
| if (memccpy (dest, &adr[outer], '\1', middle + 128) |
| != dest + inner + 1) |
| { |
| printf ("\ |
| memccpy flunked partial copy for outer = %d, middle = %d, inner = %d\n", |
| outer, middle, inner); |
| result = 1; |
| } |
| else if (dest[inner + 1] != L('\2')) |
| { |
| printf ("\ |
| memccpy copied too much for outer = %d, middle = %d, inner = %d\n", |
| outer, middle, inner); |
| result = 1; |
| } |
| adr[outer + inner] = L('\0'); |
| } |
| } |
| #endif |
| } |
| |
| return result; |
| } |
| |
| #define TEST_FUNCTION do_test () |
| #include "../test-skeleton.c" |