(root)/
glibc-2.38/
string/
test-memmove.c
       1  /* Test and measure memmove 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  #define TEST_MAIN
      20  #ifdef TEST_BCOPY
      21  # define TEST_NAME "bcopy"
      22  #else
      23  # define TEST_NAME "memmove"
      24  #endif
      25  #include "test-string.h"
      26  #include <support/test-driver.h>
      27  
      28  char *simple_memmove (char *, const char *, size_t);
      29  
      30  #ifdef TEST_BCOPY
      31  typedef void (*proto_t) (const char *, char *, size_t);
      32  
      33  IMPL (bcopy, 1)
      34  
      35  /* Naive implementation to verify results.  */
      36  void
      37  simple_bcopy (const char *src, char *dst, size_t n)
      38  {
      39    simple_memmove (dst, src, n);
      40  }
      41  
      42  #else
      43  typedef char *(*proto_t) (char *, const char *, size_t);
      44  
      45  IMPL (memmove, 1)
      46  #endif
      47  
      48  /* Naive implementation to verify results.  */
      49  char *
      50  inhibit_loop_to_libcall
      51  simple_memmove (char *dst, const char *src, size_t n)
      52  {
      53    char *ret = dst;
      54    if (src < dst)
      55      {
      56        dst += n;
      57        src += n;
      58        while (n--)
      59  	*--dst = *--src;
      60      }
      61    else
      62      while (n--)
      63        *dst++ = *src++;
      64    return ret;
      65  }
      66  
      67  static void
      68  do_one_test (impl_t *impl, char *dst, char *src, const char *orig_src,
      69  	     size_t len)
      70  {
      71    /* This also clears the destination buffer set by the previous run.  */
      72    memcpy (src, orig_src, len);
      73  #ifdef TEST_BCOPY
      74    CALL (impl, src, dst, len);
      75  #else
      76    char *res;
      77  
      78    res = CALL (impl, dst, src, len);
      79    if (res != dst)
      80      {
      81        error (0, 0, "Wrong result in function %s %p %p", impl->name,
      82  	     res, dst);
      83        ret = 1;
      84        return;
      85      }
      86  #endif
      87  
      88    if (memcmp (dst, orig_src, len) != 0)
      89      {
      90        error (0, 0, "Wrong result in function %s dst \"%s\" src \"%s\"",
      91  	     impl->name, dst, src);
      92        ret = 1;
      93        return;
      94      }
      95  }
      96  
      97  static void
      98  do_test (size_t align1, size_t align2, size_t len)
      99  {
     100    size_t i, j;
     101    char *s1, *s2;
     102  
     103    align1 &= (getpagesize() - 1);
     104    if (align1 + len >= page_size)
     105      return;
     106  
     107    align2 &= (getpagesize() - 1);
     108    if (align2 + len >= page_size)
     109      return;
     110  
     111    s1 = (char *) (buf1 + align1);
     112    s2 = (char *) (buf2 + align2);
     113  
     114    for (i = 0, j = 1; i < len; i++, j += 23)
     115      s1[i] = j;
     116  
     117    FOR_EACH_IMPL (impl, 0)
     118      do_one_test (impl, s2, (char *) (buf2 + align1), s1, len);
     119  }
     120  
     121  static void
     122  do_random_tests (void)
     123  {
     124    size_t i, n, align1, align2, len, size;
     125    size_t srcstart, srcend, dststart, dstend;
     126    int c;
     127    unsigned char *p1, *p2;
     128  #ifndef TEST_BCOPY
     129    unsigned char *res;
     130  #endif
     131  
     132    for (n = 0; n < ITERATIONS; n++)
     133      {
     134        if ((random () & 255) == 0)
     135  	size = 65536;
     136        else
     137  	size = 512;
     138        if (size > page_size)
     139  	size = page_size;
     140        if ((random () & 3) == 0)
     141  	{
     142  	  len = random () & (size - 1);
     143  	  align1 = size - len - (random () & 31);
     144  	  align2 = size - len - (random () & 31);
     145  	  if (align1 > size)
     146  	    align1 = 0;
     147  	  if (align2 > size)
     148  	    align2 = 0;
     149  	}
     150        else
     151  	{
     152  	  align1 = random () & (size / 2 - 1);
     153  	  align2 = random () & (size / 2 - 1);
     154  	  len = random () & (size - 1);
     155  	  if (align1 + len > size)
     156  	    align1 = size - len;
     157  	  if (align2 + len > size)
     158  	    align2 = size - len;
     159  	}
     160  
     161        p1 = buf1 + page_size - size;
     162        p2 = buf2 + page_size - size;
     163        c = random () & 255;
     164        srcend = align1 + len + 256;
     165        if (srcend > size)
     166  	srcend = size;
     167        if (align1 > 256)
     168  	srcstart = align1 - 256;
     169        else
     170  	srcstart = 0;
     171        for (i = srcstart; i < srcend; ++i)
     172  	p1[i] = random () & 255;
     173        dstend = align2 + len + 256;
     174        if (dstend > size)
     175  	dstend = size;
     176        if (align2 > 256)
     177  	dststart = align2 - 256;
     178        else
     179  	dststart = 0;
     180  
     181        FOR_EACH_IMPL (impl, 1)
     182  	{
     183  	  memset (p2 + dststart, c, dstend - dststart);
     184  	  memcpy (p2 + srcstart, p1 + srcstart, srcend - srcstart);
     185  #ifdef TEST_BCOPY
     186  	  CALL (impl, (char *) (p2 + align1), (char *) (p2 + align2), len);
     187  #else
     188  	  res = (unsigned char *) CALL (impl,
     189  					(char *) (p2 + align2),
     190  					(char *) (p2 + align1), len);
     191  	  if (res != p2 + align2)
     192  	    {
     193  	      error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd) %p != %p",
     194  		     n, impl->name, align1, align2, len, res, p2 + align2);
     195  	      ret = 1;
     196  	    }
     197  #endif
     198  	  if (memcmp (p1 + align1, p2 + align2, len))
     199  	    {
     200  	      error (0, 0, "Iteration %zd - different strings, %s (%zd, %zd, %zd)",
     201  		     n, impl->name, align1, align2, len);
     202  	      ret = 1;
     203  	    }
     204  	  for (i = dststart; i < dstend; ++i)
     205  	    {
     206  	      if (i >= align2 && i < align2 + len)
     207  		{
     208  		  i = align2 + len - 1;
     209  		  continue;
     210  		}
     211  	      if (i >= srcstart && i < srcend)
     212  		{
     213  		  i = srcend - 1;
     214  		  continue;
     215  		}
     216  	      if (p2[i] != c)
     217  		{
     218  		  error (0, 0, "Iteration %zd - garbage in memset area, %s (%zd, %zd, %zd)",
     219  			 n, impl->name, align1, align2, len);
     220  		  ret = 1;
     221  		  break;
     222  		}
     223  	    }
     224  
     225  	  if (srcstart < align2
     226  	      && memcmp (p2 + srcstart, p1 + srcstart,
     227  			 (srcend > align2 ? align2 : srcend) - srcstart))
     228  	    {
     229  	      error (0, 0, "Iteration %zd - garbage before dst, %s (%zd, %zd, %zd)",
     230  		     n, impl->name, align1, align2, len);
     231  	      ret = 1;
     232  	      break;
     233  	    }
     234  
     235  	  i = srcstart > align2 + len ? srcstart : align2 + len;
     236  	  if (srcend > align2 + len
     237  	      && memcmp (p2 + i, p1 + i, srcend - i))
     238  	    {
     239  	      error (0, 0, "Iteration %zd - garbage after dst, %s (%zd, %zd, %zd)",
     240  		     n, impl->name, align1, align2, len);
     241  	      ret = 1;
     242  	      break;
     243  	    }
     244  	}
     245      }
     246  }
     247  
     248  static void
     249  do_test2 (size_t offset)
     250  {
     251    size_t size = 0x20000000;
     252    uint32_t * large_buf;
     253  
     254    large_buf = mmap ((void*) 0x70000000, size, PROT_READ | PROT_WRITE,
     255  		    MAP_PRIVATE | MAP_ANON, -1, 0);
     256  
     257    if (large_buf == MAP_FAILED)
     258      error (EXIT_UNSUPPORTED, errno, "Large mmap failed");
     259  
     260    if ((uintptr_t) large_buf > 0x80000000 - 128
     261        || 0x80000000 - (uintptr_t) large_buf > 0x20000000)
     262      {
     263        error (0, 0, "Large mmap allocated improperly");
     264        ret = EXIT_UNSUPPORTED;
     265        munmap ((void *) large_buf, size);
     266        return;
     267      }
     268  
     269    size_t bytes_move = 0x80000000 - (uintptr_t) large_buf;
     270    if (bytes_move + offset * sizeof (uint32_t) > size)
     271      {
     272        munmap ((void *) large_buf, size);
     273        return;
     274      }
     275    size_t arr_size = bytes_move / sizeof (uint32_t);
     276    size_t i;
     277    size_t repeats;
     278    uint32_t * src = large_buf;
     279    uint32_t * dst = &large_buf[offset];
     280    for (repeats = 0; repeats < 2; ++repeats)
     281      {
     282        FOR_EACH_IMPL (impl, 0)
     283          {
     284            for (i = 0; i < arr_size; i++)
     285              src[i] = (uint32_t) i;
     286  
     287  
     288  #ifdef TEST_BCOPY
     289            CALL (impl, (char *) src, (char *) dst, bytes_move);
     290  #else
     291            CALL (impl, (char *) dst, (char *) src, bytes_move);
     292  #endif
     293  
     294            for (i = 0; i < arr_size; i++)
     295  	    {
     296  	      if (dst[i] != (uint32_t) i)
     297  		{
     298  		  error (0, 0,
     299  			 "Wrong result in function %s dst \"%p\" src \"%p\" offset \"%zd\"",
     300  			 impl->name, dst, src, i);
     301  		  ret = 1;
     302  		  munmap ((void *) large_buf, size);
     303  		  return;
     304  		}
     305  	    }
     306  	}
     307        src = dst;
     308        dst = large_buf;
     309      }
     310  
     311    munmap ((void *) large_buf, size);
     312  }
     313  
     314  static void
     315  do_test3 (size_t bytes_move, size_t offset)
     316  {
     317    size_t size = bytes_move * 3;
     318    uint32_t *buf;
     319  
     320    buf = mmap (NULL, size, PROT_READ | PROT_WRITE,
     321  	      MAP_PRIVATE | MAP_ANON, -1, 0);
     322  
     323    if (buf == MAP_FAILED)
     324      error (EXIT_UNSUPPORTED, errno, "mmap failed");
     325  
     326    size_t arr_size = bytes_move / sizeof (uint32_t);
     327    size_t i;
     328  
     329    FOR_EACH_IMPL (impl, 0)
     330      {
     331        for (i = 0; i < arr_size; i++)
     332          buf[i] = (uint32_t) i;
     333  
     334        uint32_t *dst = &buf[arr_size + offset];
     335  
     336  #ifdef TEST_BCOPY
     337        CALL (impl, (char *) buf, (char *) dst, bytes_move);
     338  #else
     339        CALL (impl, (char *) dst, (char *) buf, bytes_move);
     340  #endif
     341  
     342        for (i = 0; i < arr_size; i++)
     343  	{
     344  	  if (dst[i] != (uint32_t) i)
     345  	    {
     346  	      error (0, 0,
     347  		     "Wrong result in function %s dst \"%p\" src \"%p\" offset \"%zd\"",
     348  		     impl->name, dst, buf, i);
     349  	      ret = 1;
     350  	      break;
     351  	    }
     352  	}
     353      }
     354  
     355    munmap ((void *) buf, size);
     356  }
     357  
     358  static void
     359  do_test4 (size_t bytes_move, size_t offset1, size_t offset2)
     360  {
     361    size_t size, repeats, i;
     362    uint8_t *buf, *dst, *src;
     363  
     364    size = bytes_move + MAX(offset1, offset2);
     365    buf  = mmap(NULL, size, PROT_READ | PROT_WRITE,
     366               MAP_PRIVATE | MAP_ANON, -1, 0);
     367  
     368    if (buf == MAP_FAILED)
     369      error (EXIT_UNSUPPORTED, errno, "mmap failed");
     370  
     371    dst = &buf[offset1];
     372    src = &buf[offset2];
     373    for (repeats = 0; repeats < 2; ++repeats)
     374      {
     375        FOR_EACH_IMPL (impl, 0)
     376          {
     377            for (i = 0; i < bytes_move; i++)
     378                src[i] = (uint8_t) i;
     379  #ifdef TEST_BCOPY
     380            CALL (impl, (char *) src, (char *) dst, bytes_move);
     381  #else
     382            CALL (impl, (char *) dst, (char *) src, bytes_move);
     383  #endif
     384            for (i = 0; i < bytes_move; i++)
     385              {
     386                if (dst[i] != (uint8_t) i)
     387                  {
     388                    error (0, 0,
     389                           "Wrong result in function %s dst \"%p\" src \"%p\" offset \"%zd\"",
     390                           impl->name, dst, buf, i);
     391                    ret = 1;
     392                    break;
     393                  }
     394              }
     395          }
     396        dst = &buf[offset2];
     397        src = &buf[offset1];
     398      }
     399    munmap ((void *) buf, size);
     400  }
     401  
     402  
     403  int
     404  test_main (void)
     405  {
     406    size_t i;
     407  
     408    test_init ();
     409  
     410    printf ("%23s", "");
     411    FOR_EACH_IMPL (impl, 0)
     412      printf ("\t%s", impl->name);
     413    putchar ('\n');
     414  
     415    for (i = 0; i < 14; ++i)
     416      {
     417        do_test (0, 32, 1 << i);
     418        do_test (32, 0, 1 << i);
     419        do_test (0, i, 1 << i);
     420        do_test (i, 0, 1 << i);
     421      }
     422  
     423    for (i = 0; i < 32; ++i)
     424      {
     425        do_test (0, 32, i);
     426        do_test (32, 0, i);
     427        do_test (0, i, i);
     428        do_test (i, 0, i);
     429      }
     430  
     431    for (i = 3; i < 32; ++i)
     432      {
     433        if ((i & (i - 1)) == 0)
     434  	continue;
     435        do_test (0, 32, 16 * i);
     436        do_test (32, 0, 16 * i);
     437        do_test (0, i, 16 * i);
     438        do_test (i, 0, 16 * i);
     439      }
     440  
     441    do_random_tests ();
     442  
     443    do_test2 (0);
     444    do_test2 (33);
     445    do_test2 (0x200000 - 1);
     446    do_test2 (0x200000);
     447    do_test2 (0x200000 + 1);
     448    do_test2 (0x1000000 - 1);
     449    do_test2 (0x1000000);
     450    do_test2 (0x1000000 + 1);
     451    do_test2 (0x4000000 - 1);
     452    do_test2 (0x4000000);
     453    do_test2 (0x4000000 + 1);
     454  
     455    /* Copy 16KB data.  */
     456    do_test3 (16384, 3);
     457    for (i = 4096; i <= 16384; i <<= 1)
     458      {
     459        do_test4 (i, 0, i);
     460        do_test4 (i, 0, i - 1);
     461        do_test4 (i, 0, i + 1);
     462        do_test4 (i, 63, i + 63);
     463        do_test4 (i, 63, i + 64);
     464        do_test4 (i, 63, i);
     465  
     466        do_test4 (i, 0, 1);
     467        do_test4 (i, 0, 15);
     468        do_test4 (i, 0, 31);
     469        do_test4 (i, 0, 63);
     470        do_test4 (i, 0, 64);
     471        do_test4 (i, 0, 65);
     472        do_test4 (i, 0, 127);
     473        do_test4 (i, 0, 129);
     474      }
     475  
     476  
     477    return ret;
     478  }
     479  
     480  #include <support/test-driver.c>