(root)/
glibc-2.38/
string/
test-strncpy.c
       1  /* Test strncpy functions.
       2     Copyright (C) 1999-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  #ifdef WIDE
      20  # include <wchar.h>
      21  # define CHAR wchar_t
      22  # define UCHAR wchar_t
      23  # define BIG_CHAR WCHAR_MAX
      24  # define SMALL_CHAR 1273
      25  # define MEMCMP wmemcmp
      26  # define MEMSET wmemset
      27  # define STRNLEN wcsnlen
      28  #else
      29  # define CHAR char
      30  # define UCHAR unsigned char
      31  # define BIG_CHAR CHAR_MAX
      32  # define SMALL_CHAR 127
      33  # define MEMCMP memcmp
      34  # define MEMSET memset
      35  # define STRNLEN strnlen
      36  #endif /* !WIDE */
      37  
      38  
      39  #ifndef STRNCPY_RESULT
      40  # define STRNCPY_RESULT(dst, len, n) dst
      41  # define TEST_MAIN
      42  # ifndef WIDE
      43  #  define TEST_NAME "strncpy"
      44  # else
      45  #  define TEST_NAME "wcsncpy"
      46  # endif /* WIDE */
      47  # include "test-string.h"
      48  # ifndef WIDE
      49  #  define SIMPLE_STRNCPY simple_strncpy
      50  #  define STRNCPY strncpy
      51  # else
      52  #  define SIMPLE_STRNCPY simple_wcsncpy
      53  #  define STRNCPY wcsncpy
      54  # endif /* WIDE */
      55  
      56  
      57  IMPL (STRNCPY, 1)
      58  
      59  /* Naive implementation to verify results.  */
      60  CHAR *
      61  SIMPLE_STRNCPY (CHAR *dst, const CHAR *src, size_t n)
      62  {
      63    CHAR *ret = dst;
      64    while (n--)
      65      if ((*dst++ = *src++) == '\0')
      66        {
      67  	while (n--)
      68  	  *dst++ = '\0';
      69  	return ret;
      70        }
      71    return ret;
      72  }
      73  
      74  #endif /* !STRNCPY_RESULT */
      75  
      76  typedef CHAR *(*proto_t) (CHAR *, const CHAR *, size_t);
      77  
      78  static void
      79  do_one_test (impl_t *impl, CHAR *dst, const CHAR *src, size_t len, size_t n)
      80  {
      81    if (CALL (impl, dst, src, n) != STRNCPY_RESULT (dst, len, n))
      82      {
      83        error (0, 0, "Wrong result in function %s %p %p", impl->name,
      84  	     CALL (impl, dst, src, n), dst);
      85        ret = 1;
      86        return;
      87      }
      88  
      89    if (memcmp (dst, src, (len > n ? n : len) * sizeof (CHAR)) != 0)
      90      {
      91        error (0, 0, "Wrong result in function %s", impl->name);
      92        ret = 1;
      93        return;
      94      }
      95  
      96    if (n > len)
      97      {
      98        size_t i;
      99  
     100        for (i = len; i < n; ++i)
     101  	if (dst [i] != '\0')
     102  	  {
     103  	    error (0, 0, "Wrong result in function %s", impl->name);
     104  	    ret = 1;
     105  	    return;
     106  	  }
     107      }
     108  }
     109  
     110  static void
     111  do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char)
     112  {
     113    size_t i;
     114    CHAR *s1, *s2;
     115  
     116  /* For wcsncpy: align1 and align2 here mean alignment not in bytes,
     117     but in wchar_ts, in bytes it will equal to align * (sizeof (wchar_t)).  */
     118    align1 &= 7;
     119    if ((align1 + len) * sizeof (CHAR) >= page_size)
     120      return;
     121  
     122    align2 &= 7;
     123    if ((align2 + len) * sizeof (CHAR) >= page_size)
     124      return;
     125  
     126    s1 = (CHAR *) (buf1) + align1;
     127    s2 = (CHAR *) (buf2) + align2;
     128  
     129    for (i = 0; i < len; ++i)
     130      s1[i] = 32 + 23 * i % (max_char - 32);
     131    s1[len] = 0;
     132    for (i = len + 1; (i + align1) * sizeof (CHAR) < page_size && i < len + 64;
     133         ++i)
     134      s1[i] = 32 + 32 * i % (max_char - 32);
     135  
     136    FOR_EACH_IMPL (impl, 0)
     137      do_one_test (impl, s2, s1, len, n);
     138  }
     139  
     140  static void
     141  do_page_tests (void)
     142  {
     143    CHAR *s1, *s2;
     144    const size_t maxoffset = 64;
     145  
     146    /* Put s1 at the maxoffset from the edge of buf1's last page.  */
     147    s1 = (CHAR *) buf1 + BUF1PAGES * page_size / sizeof(CHAR) - maxoffset;
     148    /* s2 needs room to put a string with size of maxoffset + 1 at s2 +
     149       (maxoffset - 1).  */
     150    s2 = (CHAR *) buf2 + page_size / sizeof(CHAR) - maxoffset * 2;
     151  
     152    MEMSET (s1, 'a', maxoffset - 1);
     153    s1[maxoffset - 1] = '\0';
     154  
     155    /* Both strings are bounded to a page with read/write access and the next
     156       page is protected with PROT_NONE (meaning that any access outside of the
     157       page regions will trigger an invalid memory access).
     158  
     159       The loop copies the string s1 for all possible offsets up to maxoffset
     160       for both inputs with a size larger than s1 (so memory access outside the
     161       expected memory regions might trigger invalid access).  */
     162  
     163    for (size_t off1 = 0; off1 < maxoffset; off1++)
     164      {
     165        for (size_t off2 = 0; off2 < maxoffset; off2++)
     166  	{
     167  	  FOR_EACH_IMPL (impl, 0)
     168  	    do_one_test (impl, s2 + off2, s1 + off1, maxoffset - off1 - 1,
     169  			 maxoffset + (maxoffset - off2));
     170  	}
     171      }
     172  }
     173  
     174  static void
     175  do_random_tests (void)
     176  {
     177    size_t i, j, n, align1, align2, len, size, mode;
     178    UCHAR *p1 = (UCHAR *) (buf1 + page_size) - 512;
     179    UCHAR *p2 = (UCHAR *) (buf2 + page_size) - 512;
     180    UCHAR *res;
     181  
     182    for (n = 0; n < ITERATIONS; n++)
     183      {
     184        /* For wcsncpy: align1 and align2 here mean align not in bytes,
     185  	 but in wchar_ts, in bytes it will equal to align * (sizeof
     186  	 (wchar_t)).  */
     187  
     188        mode = random ();
     189        if (mode & 1)
     190  	{
     191  	  size = random () & 255;
     192  	  align1 = 512 - size - (random () & 15);
     193  	  if (mode & 2)
     194  	    align2 = align1 - (random () & 24);
     195  	  else
     196  	    align2 = align1 - (random () & 31);
     197  	  if (mode & 4)
     198  	    {
     199  	      j = align1;
     200  	      align1 = align2;
     201  	      align2 = j;
     202  	    }
     203  	  if (mode & 8)
     204  	    len = size - (random () & 31);
     205  	  else
     206  	    len = 512;
     207  	  if (len >= 512)
     208  	    len = random () & 511;
     209  	}
     210        else
     211  	{
     212  	  align1 = random () & 31;
     213  	  if (mode & 2)
     214  	    align2 = random () & 31;
     215  	  else
     216  	    align2 = align1 + (random () & 24);
     217  	  len = random () & 511;
     218  	  j = align1;
     219  	  if (align2 > j)
     220  	    j = align2;
     221  	  if (mode & 4)
     222  	    {
     223  	      size = random () & 511;
     224  	      if (size + j > 512)
     225  		size = 512 - j - (random () & 31);
     226  	    }
     227  	  else
     228  	    size = 512 - j;
     229  	  if ((mode & 8) && len + j >= 512)
     230  	    len = 512 - j - (random () & 7);
     231  	}
     232        j = len + align1 + 64;
     233        if (j > 512)
     234  	j = 512;
     235        for (i = 0; i < j; i++)
     236  	{
     237  	  if (i == len + align1)
     238  	    p1[i] = 0;
     239  	  else
     240  	    {
     241  	      p1[i] = random () & BIG_CHAR;
     242  	      if (i >= align1 && i < len + align1 && !p1[i])
     243  		p1[i] = (random () & SMALL_CHAR) + 3;
     244  	    }
     245  	}
     246  
     247        FOR_EACH_IMPL (impl, 1)
     248  	{
     249  	  MEMSET (p2 - 64, '\1', 512 + 64);
     250  	  res = (UCHAR *) CALL (impl, (CHAR *) (p2 + align2),
     251  				(CHAR *) (p1 + align1), size);
     252  	  if (res != STRNCPY_RESULT (p2 + align2, len, size))
     253  	    {
     254  	      error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd) %p != %p",
     255  		     n, impl->name, align1, align2, len, res,
     256  		     STRNCPY_RESULT (p2 + align2, len, size));
     257  	      ret = 1;
     258  	    }
     259  	  for (j = 0; j < align2 + 64; ++j)
     260  	    {
     261  	      if (p2[j - 64] != '\1')
     262  		{
     263  		  error (0, 0, "Iteration %zd - garbage before, %s (%zd, %zd, %zd)",
     264  			 n, impl->name, align1, align2, len);
     265  		  ret = 1;
     266  		  break;
     267  		}
     268  	    }
     269  	  j = align2 + len + 1;
     270  	  if (size + align2 > j)
     271  	    j = size + align2;
     272  	  for (; j < 512; ++j)
     273  	    {
     274  	      if (p2[j] != '\1')
     275  		{
     276  		  error (0, 0, "Iteration %zd - garbage after, %s (%zd, %zd, %zd)",
     277  			 n, impl->name, align1, align2, len);
     278  		  ret = 1;
     279  		  break;
     280  		}
     281  	    }
     282  	  for (j = align2 + len + 1; j < align2 + size; ++j)
     283  	    if (p2[j])
     284  	      {
     285  		error (0, 0, "Iteration %zd - garbage after size, %s (%zd, %zd, %zd)",
     286  		       n, impl->name, align1, align2, len);
     287  		ret = 1;
     288  		break;
     289  	      }
     290  	  j = len + 1;
     291  	  if (size < j)
     292  	    j = size;
     293  	  if (MEMCMP (p1 + align1, p2 + align2, j))
     294  	    {
     295  	      error (0, 0, "Iteration %zd - different strings, %s (%zd, %zd, %zd)",
     296  		     n, impl->name, align1, align2, len);
     297  	      ret = 1;
     298  	    }
     299  	}
     300      }
     301  }
     302  
     303  int
     304  test_main (void)
     305  {
     306    size_t i;
     307  
     308    test_init ();
     309  
     310    printf ("%28s", "");
     311    FOR_EACH_IMPL (impl, 0)
     312      printf ("\t%s", impl->name);
     313    putchar ('\n');
     314  
     315    for (i = 1; i < 8; ++i)
     316      {
     317        do_test (i, i, 16, 16, SMALL_CHAR);
     318        do_test (i, i, 16, 16, BIG_CHAR);
     319        do_test (i, 2 * i, 16, 16, SMALL_CHAR);
     320        do_test (2 * i, i, 16, 16, BIG_CHAR);
     321        do_test (8 - i, 2 * i, 1 << i, 2 << i, SMALL_CHAR);
     322        do_test (2 * i, 8 - i, 2 << i, 1 << i, SMALL_CHAR);
     323        do_test (8 - i, 2 * i, 1 << i, 2 << i, BIG_CHAR);
     324        do_test (2 * i, 8 - i, 2 << i, 1 << i, BIG_CHAR);
     325      }
     326  
     327    for (i = 1; i < 8; ++i)
     328      {
     329        do_test (0, 0, 4 << i, 8 << i, SMALL_CHAR);
     330        do_test (0, 0, 16 << i, 8 << i, SMALL_CHAR);
     331        do_test (8 - i, 2 * i, 4 << i, 8 << i, SMALL_CHAR);
     332        do_test (8 - i, 2 * i, 16 << i, 8 << i, SMALL_CHAR);
     333      }
     334  
     335    do_random_tests ();
     336    do_page_tests ();
     337    return ret;
     338  }
     339  
     340  #include <support/test-driver.c>