(root)/
glibc-2.38/
string/
test-strncat.c
       1  /* Test strncat functions.
       2     Copyright (C) 2011-2023 Free Software Foundation, Inc.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #define TEST_MAIN
      19  #ifndef WIDE
      20  # define TEST_NAME "strncat"
      21  #else
      22  # define TEST_NAME "wcsncat"
      23  #endif /* WIDE */
      24  #include "test-string.h"
      25  
      26  #ifndef WIDE
      27  # define STRNCAT strncat
      28  # define CHAR char
      29  # define UCHAR unsigned char
      30  # define SIMPLE_STRNCAT simple_strncat
      31  # define STRNLEN strnlen
      32  # define STRLEN strlen
      33  # define MEMSET memset
      34  # define MEMCPY memcpy
      35  # define MEMCMP memcmp
      36  # define BIG_CHAR CHAR_MAX
      37  # define SMALL_CHAR 127
      38  #else
      39  # include <wchar.h>
      40  # define STRNCAT wcsncat
      41  # define CHAR wchar_t
      42  # define UCHAR wchar_t
      43  # define SIMPLE_STRNCAT simple_wcsncat
      44  # define STRNLEN wcsnlen
      45  # define STRLEN wcslen
      46  # define MEMSET wmemset
      47  # define MEMCPY wmemcpy
      48  # define MEMCMP wmemcmp
      49  # define BIG_CHAR WCHAR_MAX
      50  # define SMALL_CHAR 1273
      51  #endif /* WIDE */
      52  
      53  typedef CHAR *(*proto_t) (CHAR *, const CHAR *, size_t);
      54  
      55  IMPL (STRNCAT, 2)
      56  
      57  /* Naive implementation to verify results.  */
      58  CHAR *
      59  SIMPLE_STRNCAT (CHAR *dst, const CHAR *src, size_t n)
      60  {
      61    CHAR *ret = dst;
      62    while (*dst++ != '\0');
      63    --dst;
      64    while (n--)
      65      if ((*dst++ = *src++) == '\0')
      66        return ret;
      67    *dst = '\0';
      68    return ret;
      69  }
      70  
      71  static void
      72  __attribute__((noinline))
      73  do_one_test (impl_t *impl, CHAR *dst, const CHAR *src, size_t n)
      74  {
      75    size_t k = STRLEN (dst);
      76    if (CALL (impl, dst, src, n) != dst)
      77      {
      78        error (0, 0, "Wrong result in function %s %p != %p", impl->name,
      79  	     CALL (impl, dst, src, n), dst);
      80        ret = 1;
      81        return;
      82      }
      83  
      84    size_t len = STRNLEN (src, n);
      85    if (MEMCMP (dst + k, src, len + 1 > n ? n : len + 1) != 0)
      86      {
      87        error (0, 0, "Incorrect concatenation in function %s",
      88  	     impl->name);
      89        ret = 1;
      90        return;
      91      }
      92    if (n < len && dst[k + n] != '\0')
      93      {
      94        error (0, 0, "There is no zero in the end of output string in %s",
      95  	     impl->name);
      96        ret = 1;
      97        return;
      98      }
      99  }
     100  
     101  static void
     102  do_test_src_no_nullterm_bz30065 (void)
     103  {
     104    /* NB: "src does not need to be null-terminated if it contains n or more
     105     * bytes." */
     106    CHAR *s1, *s2;
     107    size_t bound = page_size / sizeof (CHAR);
     108    s1 = (CHAR *) (buf1 + BUF1PAGES * page_size);
     109    s2 = (CHAR *) buf2;
     110    MEMSET (s1 - bound, -1, bound);
     111    for (size_t n = 0; n < bound; ++n)
     112      {
     113        FOR_EACH_IMPL (impl, 0)
     114  	{
     115  	  s2[0] = '\0';
     116  	  do_one_test (impl, s2, s1 - n, n);
     117  	}
     118      }
     119  }
     120  
     121  static void
     122  do_test (size_t align1, size_t align2, size_t len1, size_t len2,
     123  	 size_t n, int max_char)
     124  {
     125    size_t i;
     126    CHAR *s1, *s2;
     127  
     128    align1 &= 7;
     129    if ((align1 + len1) * sizeof (CHAR) >= page_size)
     130      return;
     131    if ((align1 + n) * sizeof (CHAR) > page_size)
     132      return;
     133    align2 &= 7;
     134    if ((align2 + len1 + len2) * sizeof (CHAR) >= page_size)
     135      return;
     136    if ((align2 + len1 + n) * sizeof (CHAR) > page_size)
     137      return;
     138    s1 = (CHAR *) (buf1) + align1;
     139    s2 = (CHAR *) (buf2) + align2;
     140  
     141    for (i = 0; i < len1; ++i)
     142      s1[i] = 32 + 23 * i % (max_char - 32);
     143    s1[len1] = '\0';
     144  
     145    for (i = 0; i < len2; i++)
     146      s2[i] = 32 + 23 * i % (max_char - 32);
     147  
     148    FOR_EACH_IMPL (impl, 0)
     149      {
     150        s2[len2] = '\0';
     151        do_one_test (impl, s2, s1, n);
     152      }
     153  }
     154  
     155  static void
     156  do_overflow_tests (void)
     157  {
     158    size_t i, j, len;
     159    const size_t one = 1;
     160    CHAR *s1, *s2;
     161    uintptr_t s1_addr;
     162    s1 = (CHAR *) buf1;
     163    s2 = (CHAR *) buf2;
     164    s1_addr = (uintptr_t)s1;
     165   for (j = 0; j < 200; ++j)
     166        s2[j] = 32 + 23 * j % (BIG_CHAR - 32);
     167   s2[200] = 0;
     168    for (i = 0; i < 750; ++i) {
     169      for (j = 0; j < i; ++j)
     170        s1[j] = 32 + 23 * j % (BIG_CHAR - 32);
     171      s1[i] = '\0';
     172  
     173         FOR_EACH_IMPL (impl, 0)
     174      {
     175        s2[200] = '\0';
     176        do_one_test (impl, s2, s1, SIZE_MAX - i);
     177        s2[200] = '\0';
     178        do_one_test (impl, s2, s1, i - s1_addr);
     179        s2[200] = '\0';
     180        do_one_test (impl, s2, s1, -s1_addr - i);
     181        s2[200] = '\0';
     182        do_one_test (impl, s2, s1, SIZE_MAX - s1_addr - i);
     183        s2[200] = '\0';
     184        do_one_test (impl, s2, s1, SIZE_MAX - s1_addr + i);
     185      }
     186  
     187      len = 0;
     188      for (j = 8 * sizeof(size_t) - 1; j ; --j)
     189        {
     190          len |= one << j;
     191          FOR_EACH_IMPL (impl, 0)
     192            {
     193              s2[200] = '\0';
     194              do_one_test (impl, s2, s1, len - i);
     195              s2[200] = '\0';
     196              do_one_test (impl, s2, s1, len + i);
     197              s2[200] = '\0';
     198              do_one_test (impl, s2, s1, len - s1_addr - i);
     199              s2[200] = '\0';
     200              do_one_test (impl, s2, s1, len - s1_addr + i);
     201  
     202              s2[200] = '\0';
     203              do_one_test (impl, s2, s1, ~len - i);
     204              s2[200] = '\0';
     205              do_one_test (impl, s2, s1, ~len + i);
     206              s2[200] = '\0';
     207              do_one_test (impl, s2, s1, ~len - s1_addr - i);
     208              s2[200] = '\0';
     209              do_one_test (impl, s2, s1, ~len - s1_addr + i);
     210            }
     211        }
     212    }
     213  }
     214  
     215  static void
     216  do_random_tests (void)
     217  {
     218    size_t i, j, n, align1, align2, len1, len2, N;
     219    UCHAR *p1 = (UCHAR *) (buf1 + page_size) - 512;
     220    UCHAR *p2 = (UCHAR *) (buf2 + page_size) - 512;
     221    UCHAR *p3 = (UCHAR *) buf1;
     222    UCHAR *res;
     223    fprintf (stdout, "Number of iterations in random test = %zd\n",
     224  	   ITERATIONS);
     225    for (n = 0; n < ITERATIONS; n++)
     226      {
     227        N = random () & 255;
     228        align1 = random () & 31;
     229        if (random () & 1)
     230  	align2 = random () & 31;
     231        else
     232  	align2 = align1 + (random () & 24);
     233        len1 = random () & 511;
     234        if (len1 + align2 > 512)
     235  	len2 = random () & 7;
     236        else
     237  	len2 = (512 - len1 - align2) * (random () & (1024 * 1024 - 1))
     238  	  / (1024 * 1024);
     239        j = align1;
     240        if (align2 + len2 > j)
     241  	j = align2 + len2;
     242        if (len1 + j >= 511)
     243  	len1 = 510 - j - (random () & 7);
     244        if (len1 >= 512)
     245  	len1 = 0;
     246        if (align1 + len1 < 512 - 8)
     247  	{
     248  	  j = 510 - align1 - len1 - (random () & 31);
     249  	  if (j > 0 && j < 512)
     250  	    align1 += j;
     251  	}
     252        j = len1 + align1 + 64;
     253        if (j > 512)
     254  	j = 512;
     255        for (i = 0; i < j; i++)
     256  	{
     257  	  if (i == len1 + align1)
     258  	    p1[i] = 0;
     259  	  else
     260  	    {
     261  	      p1[i] = random () & BIG_CHAR;
     262  	      if (i >= align1 && i < len1 + align1 && !p1[i])
     263  		p1[i] = (random () & SMALL_CHAR) + 3;
     264  	    }
     265  	}
     266        for (i = 0; i < len2; i++)
     267  	{
     268  	  p3[i] = random () & BIG_CHAR;
     269  	  if (!p3[i])
     270  	    p3[i] = (random () & SMALL_CHAR) + 3;
     271  	}
     272        p3[len2] = 0;
     273  
     274        FOR_EACH_IMPL (impl, 1)
     275  	{
     276  	  MEMSET (p2 - 64, '\1', align2 + 64);
     277  	  MEMSET (p2 + align2 + len2 + 1, '\1', 512 - align2 - len2 - 1);
     278  	  MEMCPY (p2 + align2, p3, len2 + 1);
     279  	  res = (UCHAR *) CALL (impl, (CHAR *) (p2 + align2),
     280  				(CHAR *) (p1 + align1), N);
     281  	  if (res != p2 + align2)
     282  	    {
     283  	      error (0, 0, "Iteration %zd - wrong result in function %s "
     284  		     "(%zd, %zd, %zd, %zd, %zd) %p != %p",
     285  		     n, impl->name, align1, align2, len1, len2, N,
     286  		     res, p2 + align2);
     287  	      ret = 1;
     288  	    }
     289  	  for (j = 0; j < align2 + 64; ++j)
     290  	    {
     291  	      if (p2[j - 64] != '\1')
     292  		{
     293  		  error (0, 0, "Iteration %zd - garbage before dst, %s "
     294  			 "%zd, %zd, %zd, %zd, %zd)",
     295  			 n, impl->name, align1, align2, len1, len2, N);
     296  		  ret = 1;
     297  		  break;
     298  		}
     299  	    }
     300  	  if (MEMCMP (p2 + align2, p3, len2))
     301  	    {
     302  	      error (0, 0, "Iteration %zd - garbage in string before, %s "
     303  		     "(%zd, %zd, %zd, %zd, %zd)",
     304  		     n, impl->name, align1, align2, len1, len2, N);
     305  	      ret = 1;
     306  	    }
     307  
     308  	  if ((len1 + 1) > N)
     309  	    j = align2 + N + 1 + len2;
     310  	  else
     311  	    j = align2 + len1 + 1 + len2;
     312  	  for (; j < 512; ++j)
     313  	    {
     314  	      if (p2[j] != '\1')
     315  		{
     316  		  error (0, 0, "Iteration %zd - garbage after, %s "
     317  			 "(%zd, %zd, %zd, %zd, %zd)",
     318  			 n, impl->name, align1, align2, len1, len2, N);
     319  		  ret = 1;
     320  		  break;
     321  		}
     322  	    }
     323  	  if (len1 + 1 > N)
     324  	    {
     325  	      if (p2[align2 + N + len2] != '\0')
     326  		{
     327  		  error (0, 0, "Iteration %zd - there is no zero at the "
     328  			 "end of output string, %s (%zd, %zd, %zd, %zd, %zd)",
     329  			 n, impl->name, align1, align2, len1, len2, N);
     330  		  ret = 1;
     331  		}
     332  	    }
     333  	  if (MEMCMP (p1 + align1, p2 + align2 + len2,
     334  		      (len1 + 1) > N ? N : len1 + 1))
     335  	    {
     336  	      error (0, 0, "Iteration %zd - different strings, %s "
     337  		     "(%zd, %zd, %zd, %zd, %zd)",
     338  		     n, impl->name, align1, align2, len1, len2, N);
     339  	      ret = 1;
     340  	    }
     341  	}
     342      }
     343  }
     344  
     345  int
     346  test_main (void)
     347  {
     348    size_t i, n;
     349  
     350    test_init ();
     351  
     352    printf ("%28s", "");
     353    FOR_EACH_IMPL (impl, 0)
     354      printf ("\t%s", impl->name);
     355    putchar ('\n');
     356  
     357    for (n = 2; n <= 2048; n*=4)
     358      {
     359        do_test (0, 2, 2, 2, n, SMALL_CHAR);
     360        do_test (0, 0, 4, 4, n, SMALL_CHAR);
     361        do_test (4, 0, 4, 4, n, BIG_CHAR);
     362        do_test (0, 0, 8, 8, n, SMALL_CHAR);
     363        do_test (0, 8, 8, 8, n, SMALL_CHAR);
     364  
     365        do_test (0, 2, 2, 2, SIZE_MAX, SMALL_CHAR);
     366        do_test (0, 0, 4, 4, SIZE_MAX, SMALL_CHAR);
     367        do_test (4, 0, 4, 4, SIZE_MAX, BIG_CHAR);
     368        do_test (0, 0, 8, 8, SIZE_MAX, SMALL_CHAR);
     369        do_test (0, 8, 8, 8, SIZE_MAX, SMALL_CHAR);
     370  
     371        for (i = 1; i < 8; ++i)
     372  	{
     373  	  do_test (0, 0, 8 << i, 8 << i, n, SMALL_CHAR);
     374  	  do_test (8 - i, 2 * i, 8 << i, 8 << i, n, SMALL_CHAR);
     375  	  do_test (0, 0, 8 << i, 2 << i, n, SMALL_CHAR);
     376  	  do_test (8 - i, 2 * i, 8 << i, 2 << i, n, SMALL_CHAR);
     377  
     378  	  do_test (0, 0, 8 << i, 8 << i, SIZE_MAX, SMALL_CHAR);
     379  	  do_test (8 - i, 2 * i, 8 << i, 8 << i, SIZE_MAX, SMALL_CHAR);
     380  	  do_test (0, 0, 8 << i, 2 << i, SIZE_MAX, SMALL_CHAR);
     381  	  do_test (8 - i, 2 * i, 8 << i, 2 << i, SIZE_MAX, SMALL_CHAR);
     382  	}
     383  
     384        for (i = 1; i < 8; ++i)
     385  	{
     386  	  do_test (i, 2 * i, 8 << i, 1, n, SMALL_CHAR);
     387  	  do_test (2 * i, i, 8 << i, 1, n, BIG_CHAR);
     388  	  do_test (i, i, 8 << i, 10, n, SMALL_CHAR);
     389  
     390  	  do_test (i, 2 * i, 8 << i, 1, SIZE_MAX, SMALL_CHAR);
     391  	  do_test (2 * i, i, 8 << i, 1, SIZE_MAX, BIG_CHAR);
     392  	  do_test (i, i, 8 << i, 10, SIZE_MAX, SMALL_CHAR);
     393  	}
     394      }
     395  
     396    do_random_tests ();
     397    do_overflow_tests ();
     398    do_test_src_no_nullterm_bz30065 ();
     399    return ret;
     400  }
     401  
     402  #include <support/test-driver.c>