(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.dg/
builtin-stringop-chk-8.c
       1  /* Test exercising -Wstringop-overread warnings for reading past the end.  */
       2  /* { dg-do compile } */
       3  /* { dg-options "-O2 -Wstringop-overread -ftrack-macro-expansion=0" } */
       4  
       5  #define PTRDIFF_MAX   __PTRDIFF_MAX__
       6  #define SIZE_MAX      __SIZE_MAX__
       7  
       8  #define offsetof(type, mem)   __builtin_offsetof (type, mem)
       9  
      10  /* Return the number of bytes from member MEM of TYPE to the end
      11     of object OBJ.  */
      12  #define offsetfrom(type, obj, mem) (sizeof (obj) - offsetof (type, mem))
      13  
      14  
      15  typedef __SIZE_TYPE__ size_t;
      16  extern void* memchr (const void*, int, size_t);
      17  extern int memcmp (const void*, const void*, size_t);
      18  extern void* memcpy (void*, const void*, size_t);
      19  extern void* memmove (void*, const void*, size_t);
      20  extern void* mempcpy (void*, const void*, size_t);
      21  
      22  #define memchr(d, s, n) sink (memchr (d, s, n))
      23  #define memcmp(d, s, n) sink (d, memcmp (d, s, n))
      24  #define memcpy(d, s, n) sink (memcpy (d, s, n))
      25  #define memmove(d, s, n) sink (memmove (d, s, n))
      26  #define mempcpy(d, s, n) sink (mempcpy (d, s, n))
      27  
      28  struct A { char a, b; };
      29  struct B { struct A a; char c, d; };
      30  
      31  /* Function to call to "escape" pointers from tests below to prevent
      32     GCC from assuming the values of the objects they point to stay
      33     the unchanged.  */
      34  void sink (void*, ...);
      35  
      36  /* Function to "generate" a random number each time it's called.  Declared
      37     (but not defined) and used to prevent GCC from making assumptions about
      38     their values based on the variables uses in the tested expressions.  */
      39  size_t random_unsigned_value (void);
      40  
      41  /* Return a random unsigned value between MIN and MAX.  */
      42  
      43  static inline size_t
      44  range (size_t min, size_t max)
      45  {
      46    const size_t val = random_unsigned_value ();
      47    return val < min || max < val ? min : val;
      48  }
      49  
      50  #define R(min, max)   range (min, max)
      51  
      52  /* Verify that reading beyond the end of a local array is diagnosed.  */
      53  
      54  void test_memop_warn_local (void *p, const void *q)
      55  {
      56    memcpy (p, "1234", R (6, 7));   /* { dg-warning "reading between 6 and 7 bytes from a region of size 5" } */
      57  
      58    struct A a[2];
      59  
      60    memcpy (p, a, R (7, 8));   /* { dg-warning "reading between 7 and 8 bytes from a region of size 4" } */
      61  
      62    /* At -Wstringop-overflow=1 the destination is considered to be
      63       the whole array and its size is therefore sizeof a.  */
      64    memcpy (p, &a[0], R (8, 9));   /* { dg-warning "reading between 8 and 9 bytes from a region of size 4" } */
      65  
      66    /* Verify the same as above but by reading from the first mmeber
      67       of the first element of the array.  */
      68    memcpy (p, &a[0].a, R (8, 9));   /* { dg-warning "reading between 8 and 9 bytes from a region of size 4" } */
      69  
      70    struct B b[2];
      71  
      72    memcpy (p, &b[0], R (12, 32));   /* { dg-warning "reading between 12 and 32 bytes from a region of size 8" } */
      73  
      74    /* Verify memchr/memcmp.  */
      75    int i = R (0, 255);
      76    memchr ("", i, 2);   /* { dg-warning "specified bound 2 exceeds source size 1" "memchr" } */
      77    memchr ("", i, 2);   /* { dg-warning "specified bound 2 exceeds source size 1" "memchr" } */
      78    memchr ("123", i, 5);   /* { dg-warning "specified bound 5 exceeds source size 4" "memchr" } */
      79    memchr (a, i, sizeof a + 1);   /* { dg-warning "specified bound 5 exceeds source size 4" "memchr" } */
      80  
      81    memcmp (p, "", 2);   /* { dg-warning "specified bound 2 exceeds source size 1" "memcmp" } */
      82    memcmp (p, "123", 5);   /* { dg-warning "specified bound 5 exceeds source size 4" "memcmp" } */
      83    memcmp (p, a, sizeof a + 1);   /* { dg-warning "specified bound 5 exceeds source size 4" "memcmp" } */
      84  
      85    size_t n = PTRDIFF_MAX + (size_t)1;
      86    memchr (p, 1, n);   /* { dg-warning "exceeds maximum object size" "memchr" } */
      87    memcmp (p, q, n);   /* { dg-warning "exceeds maximum object size" "memcmp" } */
      88  
      89    n = SIZE_MAX;
      90    memchr (p, 1, n);   /* { dg-warning "exceeds maximum object size" "memchr" } */
      91    memcmp (p, q, n);   /* { dg-warning "exceeds maximum object size" "memcmp" } */
      92  }
      93  
      94  /* Verify that reading beyond the end of a dynamically allocated array
      95     of known size is diagnosed.  */
      96  
      97  void test_memop_warn_alloc (void *p)
      98  {
      99    size_t n;
     100  
     101    n = range (8, 32);
     102  
     103    struct A *a = __builtin_malloc (sizeof *a * 2);
     104  
     105    memcpy (p, a, n);   /* { dg-warning "reading between 8 and 32 bytes from a region of size 4" "memcpy from allocated" } */
     106  
     107    memcpy (p, &a[0], n);   /* { dg-warning "reading between 8 and 32 bytes from a region of size 4" "memcpy from allocated" } */
     108  
     109    memcpy (p, &a[0].a, n);   /* { dg-warning "reading between 8 and 32 bytes from a region of size " "memcpy from allocated" } */
     110  
     111    n = range (12, 32);
     112  
     113    struct B *b = __builtin_malloc (sizeof *b * 2);
     114  
     115    memcpy (p, &b[0], n);   /* { dg-warning "reading between 12 and 32 bytes from a region of size 8" "memcpy from allocated" } */
     116  
     117    /* Verify memchr/memcmp.  */
     118    n = sizeof *b * 2 + 1;
     119  
     120    memchr (b, 1, n);   /* { dg-warning "specified bound 9 exceeds source size 8" "memchr from allocated" } */
     121    memcmp (p, b, n);   /* { dg-warning "specified bound 9 exceeds source size 8" "memcmp from allocated" } */
     122  }
     123  
     124  
     125  void test_memop_nowarn (void *p)
     126  {
     127    struct B b[2];
     128  
     129    size_t n = range (sizeof b, 32);
     130  
     131    /* Verify that copying the whole array is not diagnosed regardless
     132       of whether the expression pointing to its beginning is obtained
     133       from the array itself or its first member(s).  */
     134    memcpy (p, b, n);
     135  
     136    memcpy (p, &b[0], n);
     137  
     138    memcpy (p, &b[0].a, n);
     139  
     140    memcpy (p, &b[0].a.a, n);
     141  
     142    /* Verify that memchr/memcmp doesn't cause a warning.  */
     143    memchr (p, 1, n);
     144    memchr (b, 2, n);
     145    memchr (&b[0], 3, n);
     146    memchr (&b[0].a, 4, n);
     147    memchr (&b[0].a.a, 5, n);
     148    memchr ("01234567", R (0, 255), n);
     149  
     150    memcmp (p, p, n);
     151    memcmp (p, b, n);
     152    memcmp (p, &b[0], n);
     153    memcmp (p, &b[0].a, n);
     154    memcmp (p, &b[0].a.a, n);
     155    memcmp (p, "01234567", n);
     156  }
     157  
     158  
     159  /* The following function could specify in its API that it takes
     160     an array of exactly two elements, as shown below (or simply be
     161     called with such an array).  Verify that reading from both
     162     elements is not diagnosed.  */
     163  void test_memop_nowarn_arg (void*, const struct A[2]);
     164  
     165  void test_memop_nowarn_arg (void *p, const struct A *a)
     166  {
     167    memcpy (p, a, 2 * sizeof *a);
     168  
     169    memcpy (p, a, range (2 * sizeof *a, 123));
     170  
     171    memchr (p, 1, 1234);
     172    memcmp (p, a, 1234);
     173  }