(root)/
glibc-2.38/
string/
tst-memmove-overflow.c
       1  /* Test for signed comparison bug in memmove (bug 25620).
       2     Copyright (C) 2020-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  /* This test shifts a memory region which is a bit larger than 2 GiB
      20     by one byte.  In order to make it more likely that the memory
      21     allocation succeeds on 32-bit systems, most of the allocation
      22     consists of shared pages.  Only a portion at the start and end of
      23     the allocation are unshared, and contain a specific non-repeating
      24     bit pattern.  */
      25  
      26  #include <array_length.h>
      27  #include <libc-diag.h>
      28  #include <stdint.h>
      29  #include <string.h>
      30  #include <support/blob_repeat.h>
      31  #include <support/check.h>
      32  #include <support/xunistd.h>
      33  #include <sys/mman.h>
      34  #include <unistd.h>
      35  
      36  #define TEST_MAIN
      37  #define TEST_NAME "memmove"
      38  #include "test-string.h"
      39  #include <support/test-driver.h>
      40  
      41  IMPL (memmove, 1)
      42  
      43  /* Size of the part of the allocation which is not shared, at the
      44     start and the end of the overall allocation.  4 MiB.  */
      45  enum { unshared_size = (size_t) 4U << 20 };
      46  
      47  /* The allocation is 2 GiB plus 8 MiB.  This should work with all page
      48     sizes that occur in practice.  */
      49  enum { allocation_size = ((size_t) 2U << 30) + 2 * unshared_size };
      50  
      51  /* Compute the expected byte at the given index.  This is used to
      52     produce a non-repeating pattern.  */
      53  static inline unsigned char
      54  expected_value (size_t index)
      55  {
      56    uint32_t randomized = 0x9e3779b9 * index; /* Based on golden ratio.  */
      57    return randomized >> 25;	/* Result is in the range [0, 127].  */
      58  }
      59  
      60  /* Used to count mismatches up to a limit, to avoid creating a huge
      61     test output file.  */
      62  static unsigned int mismatch_count;
      63  
      64  /* Check ACTUAL == EXPECTED.  Use INDEX for error reporting.  Exit the
      65     process after too many errors.  */
      66  static inline void
      67  check_one_index (size_t index, unsigned char actual, unsigned char expected)
      68  {
      69    if (actual != expected)
      70      {
      71        printf ("error: mismatch at index %zu: expected 0x%02x, got 0x%02x\n",
      72  	      index, actual, expected);
      73        ++mismatch_count;
      74        if (mismatch_count > 200)
      75  	FAIL_EXIT1 ("bailing out due to too many errors");
      76      }
      77  }
      78  
      79  static int
      80  test_main (void)
      81  {
      82    test_init ();
      83  
      84    FOR_EACH_IMPL (impl, 0)
      85      {
      86        printf ("info: testing %s\n", impl->name);
      87  
      88        /* Check that the allocation sizes are multiples of the page
      89  	 size.  */
      90        TEST_COMPARE (allocation_size % xsysconf (_SC_PAGESIZE), 0);
      91        TEST_COMPARE (unshared_size % xsysconf (_SC_PAGESIZE), 0);
      92  
      93        /* The repeating pattern has the MSB set in all bytes.  */
      94        unsigned char repeating_pattern[128];
      95        for (unsigned int i = 0; i < array_length (repeating_pattern); ++i)
      96  	repeating_pattern[i] = 0x80 | i;
      97  
      98        struct support_blob_repeat repeat
      99  	= support_blob_repeat_allocate_shared (repeating_pattern,
     100  					       sizeof (repeating_pattern),
     101  					       (allocation_size
     102  						/ sizeof (repeating_pattern)));
     103        if (repeat.start == NULL)
     104  	FAIL_UNSUPPORTED ("repeated blob allocation failed: %m");
     105        TEST_COMPARE (repeat.size, allocation_size);
     106  
     107        /* Unshared the start and the end of the allocation.  */
     108        unsigned char *start = repeat.start;
     109        xmmap (start, unshared_size,
     110  	     PROT_READ | PROT_WRITE,
     111  	     MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1);
     112        xmmap (start + allocation_size - unshared_size, unshared_size,
     113  	     PROT_READ | PROT_WRITE,
     114  	     MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1);
     115  
     116        /* Initialize the non-repeating pattern.  */
     117        for (size_t i = 0; i < unshared_size; ++i)
     118  	start[i] = expected_value (i);
     119        for (size_t i = allocation_size - unshared_size; i < allocation_size;
     120  	   ++i)
     121  	start[i] = expected_value (i);
     122  
     123        /* Make sure that there was really no sharing.  */
     124        asm volatile ("" ::: "memory");
     125        for (size_t i = 0; i < unshared_size; ++i)
     126  	TEST_COMPARE (start[i], expected_value (i));
     127        for (size_t i = allocation_size - unshared_size; i < allocation_size;
     128  	   ++i)
     129  	TEST_COMPARE (start[i], expected_value (i));
     130  
     131        /* Used for a nicer error diagnostic using
     132  	 TEST_COMPARE_BLOB.  */
     133        unsigned char expected_start[128];
     134        memcpy (expected_start, start + 1, sizeof (expected_start));
     135        unsigned char expected_end[128];
     136        memcpy (expected_end,
     137  	      start + allocation_size - sizeof (expected_end),
     138  	      sizeof (expected_end));
     139  
     140        /* Move the entire allocation forward by one byte.  */
     141        DIAG_PUSH_NEEDS_COMMENT;
     142  #if __GNUC_PREREQ (8, 0)
     143        /* GCC 8 warns about string function argument overflows.  */
     144        DIAG_IGNORE_NEEDS_COMMENT (8, "-Warray-bounds");
     145        DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-overflow");
     146  #endif
     147        memmove (start, start + 1, allocation_size - 1);
     148        DIAG_POP_NEEDS_COMMENT;
     149  
     150        /* Check that the unshared of the memory region have been
     151  	 shifted as expected.  The TEST_COMPARE_BLOB checks are
     152  	 redundant, but produce nicer diagnostics.  */
     153        asm volatile ("" ::: "memory");
     154        TEST_COMPARE_BLOB (expected_start, sizeof (expected_start),
     155  			 start, sizeof (expected_start));
     156        TEST_COMPARE_BLOB (expected_end, sizeof (expected_end),
     157  			 start + allocation_size - sizeof (expected_end) - 1,
     158  			 sizeof (expected_end));
     159        for (size_t i = 0; i < unshared_size - 1; ++i)
     160  	check_one_index (i, start[i], expected_value (i + 1));
     161        /* The gap between the checked start and end area of the mapping
     162  	 has shared mappings at unspecified boundaries, so do not
     163  	 check the expected values in the middle.  */
     164        for (size_t i = allocation_size - unshared_size; i < allocation_size - 1;
     165  	   ++i)
     166  	check_one_index (i, start[i], expected_value (i + 1));
     167  
     168        support_blob_repeat_free (&repeat);
     169      }
     170  
     171    return 0;
     172  }
     173  
     174  #include <support/test-driver.c>