(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.dg/
Wstringop-overflow-28.c
       1  /* PR middle-end/91582 - missing heap overflow detection for strcpy
       2     { dg-do compile }
       3     { dg-options "-O2 -Wall -Wno-array-bounds -ftrack-macro-expansion=0" } */
       4  
       5  #include "range.h"
       6  
       7  #define INT_MAX     __INT_MAX__
       8  #define INT_MIN     (-INT_MAX - 1)
       9  
      10  #define ATTR(...)   __attribute__ ((__VA_ARGS__))
      11  #define NOIPA       ATTR (noipa)
      12  
      13  extern void* alloca (size_t);
      14  extern void* calloc (size_t, size_t);
      15  extern void* malloc (size_t);
      16  
      17  extern ATTR (alloc_size (1), malloc) char* alloc1 (size_t);
      18  extern ATTR (alloc_size (1, 2), malloc) char* alloc2 (size_t, size_t);
      19  
      20  extern char* strcpy (char*, const char*);
      21  
      22  void sink (void*, ...);
      23  
      24  
      25  /* Verify warning in stores to an object of variable size N in a known
      26     range, at an offset (N + I) with a constant I.  */
      27  
      28  void same_size_and_offset_idx_cst (void)
      29  {
      30  #define T(size, off, idx) do {			\
      31      size_t n_ = size;				\
      32      ptrdiff_t i_ = idx;				\
      33      char *p_ = alloc1 (n_);			\
      34      p_ += off;					\
      35      p_[i_] = 0;					\
      36      sink (p_);					\
      37    } while (0)
      38  
      39    {
      40      const size_t n = UR (2, 3);
      41  
      42      T (n, n, -4);   // { dg-warning "writing 1 byte into a region of size 0" }
      43                      // { dg-message "at offset \\\[-2, -1] into destination object of size \\\[2, 3] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
      44      T (n, n, -3);
      45      T (n, n, -2);
      46      T (n, n, -1);
      47      T (n, n,  0);
      48      T (n, n,  1);   // { dg-warning "writing 1 byte into a region of size 0" }
      49                      // { dg-message "at offset 3 into destination object of size \\\[2, 3] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
      50    }
      51  
      52    {
      53      const size_t n = UR (3, 4);
      54  
      55      T (n, n, -5);   // { dg-warning "writing 1 byte into a region of size 0" }
      56                      // { dg-message "at offset \\\[-2, -1] into destination object of size \\\[3, 4] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
      57      T (n, n, -4);
      58      T (n, n, -3);
      59      T (n, n, -2);
      60      T (n, n, -1);
      61      T (n, n,  0);
      62      T (n, n,  1);   // { dg-warning "writing 1 byte into a region of size 0" }
      63                      // { dg-message "at offset 4 into destination object of size \\\[3, 4] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
      64    }
      65  
      66    {
      67      const size_t n = UR (5, SIZE_MAX - 2);
      68      T (n, n, -1);
      69      T (n, n, -1);
      70      T (n, n, -1);
      71      T (n, n, -1);
      72    }
      73  }
      74  
      75  
      76  /* Verify warning in stores to an object of variable size N in a known
      77     range, at an offset (M + I) with a variable M in some range and
      78     constant I.  */
      79  
      80  void different_size_and_offset_idx_cst (void)
      81  {
      82    {
      83      const size_t n = UR (2, 3);
      84      const size_t i = UR (1, 2);
      85  
      86      T (n, i, -4);   // { dg-warning "writing 1 byte into a region of size 0" }
      87                      // { dg-message "at offset \\\[-3, -2] into destination object of size \\\[2, 3] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
      88      T (n, i, -3);   // { dg-warning "writing 1 byte into a region of size 0" }
      89                      // { dg-message "at offset \\\[-2, -1] into destination object of size \\\[2, 3] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
      90      T (n, i, -2);
      91      T (n, i, -1);
      92      T (n, i,  0);
      93      T (n, i,  1);
      94      T (n, i,  2);   // { dg-warning "writing 1 byte into a region of size 0" }
      95                      // { dg-message "at offset 3 into destination object of size \\\[2, 3] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
      96    }
      97  
      98    {
      99      const size_t n = UR (3, 4);
     100      const size_t i = UR (2, 5);
     101  
     102      T (n, i, -6);   // { dg-warning "writing 1 byte into a region of size 0" }
     103                      // { dg-message "at offset \\\[-4, -2] into destination object of size \\\[3, 4] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
     104  
     105      /* The offset -5 is necessarily invalid even if the sum (i - 5) is (or
     106         could be) in bounds because it implies that the intermediate offset
     107         (p + i) is out of bounds.  */
     108      T (n, i, -5);   // { dg-warning "writing 1 byte into a region of size 0 " }
     109      T (n, i, -4);
     110      T (n, i, -3);
     111      T (n, i, -2);
     112      T (n, i, -1);
     113      T (n, i,  0);
     114      T (n, i,  1);
     115      T (n, i,  2);   // { dg-warning "writing 1 byte into a region of size 0" }
     116                      // { dg-message "at offset 4 into destination object of size \\\[3, 4] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
     117    }
     118  }
     119  
     120  
     121  /* Verify warning in stores to an object of variable size N in a known
     122     range, at an offset (M + I) with a variable M in some range and
     123     constant I.  */
     124  void different_size_and_offset_idx_var (void)
     125  {
     126    {
     127      const size_t n = UR (3, 4);
     128      const size_t i = UR (1, 2);
     129  
     130      T (n, i, SR (DIFF_MIN, 0));
     131      T (n, i, SR (      -3, 0));
     132      T (n, i, SR (      -1, 0));
     133      T (n, i, SR (       0, 1));
     134      T (n, i, SR (       1, 2));
     135      T (n, i, SR (       2, 3));
     136      T (n, i, SR (       3, 4));    // { dg-warning "\\\[-Wstringop-overflow" }
     137                                     // { dg-message "at offset 4 into destination object of size \\\[3, 4] allocated by 'alloc1'" "pr92940 note: offset addition" { target *-*-* } .-1 }
     138   }
     139  }
     140  
     141  
     142  void ptr_add_2 (int n, int i0, int i1)
     143  {
     144    if (n < 1 || 2 < n) n = 2;
     145  
     146    if (i0 < 0 || 1 < i0) i0 = 0;
     147    if (i1 < 1 || 2 < i1) i1 = 1;
     148  
     149    char *p = (char*)__builtin_malloc (n);
     150    char *q = p;
     151  
     152    q += i0;
     153    q[0] = 0;   // p[0]
     154    q += i1;
     155    q[0] = 1;   // p[1]     // { dg-warning "\\\[-Wstringop-overflow" "" { target { vect_slp_v2qi_store_unalign } } }
     156    q[1] = 2;   // p[2]     // { dg-warning "\\\[-Wstringop-overflow" "" { xfail { vect_slp_v2qi_store_unalign } } }
     157  
     158    sink (p, q);
     159  }
     160  
     161  void ptr_add_3 (int n, int i0, int i1, int i2)
     162  {
     163    if (n < 3 || 4 < n) n = 3;
     164  
     165    if (i0 < 0 || 1 < i0) i0 = 0;
     166    if (i1 < 1 || 2 < i1) i1 = 1;
     167    if (i2 < 2 || 3 < i2) i2 = 2;
     168  
     169    char *p = (char*)__builtin_malloc (n);
     170    char *q = p;
     171  
     172    q += i0;
     173    q[0] = 0;   // p[0]
     174    q += i1;
     175    q[0] = 1;   // p[1]
     176    q[1] = 2;   // p[2]
     177    q += i2;
     178    q[0] = 3;   // p[3]     // { dg-warning "\\\[-Wstringop-overflow" "" { target { vect_slp_v2qi_store_unalign } } }
     179    q[1] = 4;   // p[4]     // { dg-warning "\\\[-Wstringop-overflow" "" { xfail { vect_slp_v2qi_store_unalign } } }
     180  
     181    sink (p, q);
     182  }
     183  
     184  void ptr_add_4 (int n, int i0, int i1, int i2, int i3)
     185  {
     186    if (n < 7 || 8 < n) n = 7;
     187  
     188    if (i0 < 0 || 1 < i0) i0 = 0;
     189    if (i1 < 1 || 2 < i1) i1 = 1;
     190    if (i2 < 2 || 3 < i2) i2 = 2;
     191    if (i3 < 3 || 4 < i3) i3 = 3;
     192  
     193    char *p = (char*)__builtin_malloc (n);
     194    char *q = p;
     195  
     196    q += i0;
     197    q[0] = 0;   // p[0]
     198    q += i1;
     199    q[0] = 1;   // p[1]
     200    q[1] = 2;   // p[2]
     201    q += i2;
     202    q[0] = 3;   // p[3]
     203    q[1] = 4;   // p[4]
     204    q[2] = 5;   // p[5]
     205    q += i3;
     206    q[0] = 6;   // p[6]
     207    q[1] = 7;   // p[7]
     208    q[2] = 8;   // p[8]     // { dg-warning "\\\[-Wstringop-overflow" }
     209  
     210    sink (p, q);
     211  }
     212  
     213  void ptr_sub_from_end (int n, int i0, int i1, int i2, int i3)
     214  {
     215    if (n < 1 || 2 < n) n = 2;
     216  
     217    char *p = (char*)__builtin_malloc (n);
     218    char *q = p;
     219  
     220    // The following isn't diagnosed due to a bug/limitation.
     221    q += n;      //  N=1     N=2
     222    q[-1] = 0;   // p[0]    p[1]
     223    q[-2] = 1;   // p[-1]   p[0]
     224    q[-3] = 2;   // p[-2]   p[-1]   // { dg-warning "\\\[-Wstringop-overflow" "pr92939: negative offset from end" }
     225  
     226    /* The following isn't diagnosed because the warning doesn't recognize
     227       the index below as necessarily having the same value as the size
     228       argument to malloc.  All it considers is the range.  */
     229    q[0] = 2;                       // { dg-warning "\\\[-Wstringop-overflow" "pr92937: store just past the end" { xfail *-*-* } }
     230    q[1] = 3;                       // { dg-warning "\\\[-Wstringop-overflow" }
     231  
     232    sink (p, q);
     233  }