(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.dg/
builtin-stringop-chk-6.c
       1  /* Test exercising -Wrawmem-overflow and -Wstringop-overflow warnings.  */
       2  /* { dg-do compile } */
       3  /* { dg-options "-O2 -Wstringop-overflow=2" } */
       4  
       5  #define offsetof(type, mem)   __builtin_offsetof (type, mem)
       6  
       7  /* Return the number of bytes from member MEM of TYPE to the end
       8     of object OBJ.  */
       9  #define offsetfrom(type, obj, mem) (sizeof (obj) - offsetof (type, mem))
      10  
      11  
      12  typedef __SIZE_TYPE__ size_t;
      13  extern void* memcpy (void*, const void*, size_t);
      14  extern void* memset (void*, int, __SIZE_TYPE__);
      15  
      16  
      17  struct A { char a, b; };
      18  struct B { struct A a; char c, d; };
      19  
      20  /* Function to call to "escape" pointers from tests below to prevent
      21     GCC from assuming the values of the objects they point to stay
      22     the unchanged.  */
      23  void escape (void*, ...);
      24  
      25  /* Function to "generate" a random number each time it's called.  Declared
      26     (but not defined) and used to prevent GCC from making assumptions about
      27     their values based on the variables uses in the tested expressions.  */
      28  size_t random_unsigned_value (void);
      29  
      30  /* Return a random unsigned value between MIN and MAX.  */
      31  
      32  static inline size_t
      33  range (size_t min, size_t max)
      34  {
      35    const size_t val = random_unsigned_value ();
      36    return val < min || max < val ? min : val;
      37  }
      38  
      39  
      40  void test_memop_warn_object (const void *src)
      41  {
      42    unsigned n = range (17, 29);
      43  
      44    struct A a[2];
      45  
      46    /* At both -Wstringop-overflow=2, like at 1, the destination of functions
      47       that operate on raw memory is considered to be the whole array and its
      48       size is therefore sizeof a.  */
      49    memcpy (&a[0], src, n);   /* { dg-warning "writing between 17 and 29 bytes into a region of size 4 overflows the destination" } */
      50    escape (a);
      51  }
      52  
      53  void test_memop_warn_subobject (const void *src)
      54  {
      55    unsigned n = range (17, 31);
      56  
      57    struct B b[2];
      58  
      59    /* At -Wrawmem-overflow=2 the destination is considered to be
      60       the member sobobject of the first array element and its size
      61       is therefore sizeof b[0].a.  */
      62    memcpy (&b[0].a, src, n);   /* { dg-warning "writing between 17 and 31 bytes into a region of size 8 overflows the destination" } */
      63  
      64    escape (b);
      65  }
      66  
      67  void test_memop_nowarn_subobject (void)
      68  {
      69    struct B b[2];
      70  
      71    /* The following idiom of clearing multiple members of a struct
      72       has been seen in a few places in the Linux kernel.  Verify
      73       that a warning is not issued for it.  */
      74    memset (&b[0].c, 0, sizeof b[0] - offsetof (struct B, c));
      75  
      76    escape (b);
      77  }
      78  
      79  struct C { char a[3], b; };
      80  struct D { struct C c; char d, e; };
      81  
      82  extern char* strncpy (char*, const char*, __SIZE_TYPE__);
      83  
      84  void test_stringop_warn_object (const char *str)
      85  {
      86    unsigned n = range (2 * sizeof (struct D), 32);
      87  
      88    struct C c[2];
      89  
      90    /* Similarly, at -Wstringop-overflow=2 the destination is considered
      91       to be the array member of the first element of the array c and its
      92       size is therefore sizeof c[0].a.  */
      93    strncpy (c[0].a, "123", n);   /* { dg-warning "writing between 12 and 32 bytes into a region of size 3 overflows the destination" } */
      94    escape (c);
      95  
      96    strncpy (c[0].a, str, n);   /* { dg-warning "writing between 12 and 32 bytes into a region of size 3 overflows the destination" } */
      97    escape (c);
      98  }
      99  
     100  void test_stringop_warn_subobject (const char *src)
     101  {
     102    unsigned n = range (2 * sizeof (struct D), 32);
     103  
     104    struct D d[2];
     105  
     106    /* Same as above.  */
     107    strncpy (d[0].c.a, "123", n);   /* { dg-warning "writing between 12 and 32 bytes into a region of size 3 overflows the destination" } */
     108    escape (d);
     109  
     110    strncpy (d[0].c.a, src, n);   /* { dg-warning "writing between 12 and 32 bytes into a region of size 3 overflows the destination" } */
     111    escape (d);
     112  }