(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.dg/
Wstringop-overflow-23.c
       1  /* PR middle-end/83859 - attribute to establish relation between parameters
       2     for buffer and its size
       3     Test to verify that with optimization enabled, -Wstringop-overflow
       4     warnings are issued for calls to user-defined functions with attribute
       5     access and with non-constant out-of-bounds arguments.
       6     { dg-do compile }
       7     { dg-options "-O2 -Wall" }
       8     { dg-require-effective-target alloca } */
       9  
      10  #include "range.h"
      11  
      12  #define INT_MAX   __INT_MAX__
      13  #define INT_MIN   (-INT_MAX - 1)
      14  
      15  #define RDONLY(...)  __attribute__ ((access (read_only, __VA_ARGS__)))
      16  #define WRONLY(...)  __attribute__ ((access (write_only, __VA_ARGS__)))
      17  #define RDWR(...)  __attribute__ ((access (read_write, __VA_ARGS__)))
      18  
      19  typedef __INT32_TYPE__ int32_t;
      20  
      21  /* Exercise null pointer detection.  */
      22  
      23  RDONLY (2, 1) void
      24  rd2_1 (int, const void*);       // { dg-message "in a call to function 'rd2_1' declared with attribute 'access \\\(read_only, 2, 1\\\)" "note" }
      25  
      26  void test_rd2_1 (void)
      27  {
      28    {
      29      void *null = 0;
      30      void *p = &null;
      31  
      32      rd2_1 (0, null);
      33      rd2_1 (1, p);
      34    }
      35  
      36    {
      37      void *null = 0;
      38      rd2_1 (1, null);            // { dg-warning "argument 2 is null but the corresponding size argument 1 value is 1" }
      39    }
      40  
      41    {
      42      void *null = 0;
      43      /* Ideally the message would say "range" for a range and "value"
      44         for a singular value but using the same reduces the complexity
      45         of the code and keeps down the number of messages that need to
      46         be translated, withot sacrificing (too much) clarity.  */
      47      rd2_1 (SR (1, 2), null);    // { dg-warning "argument 2 is null but the corresponding size argument 1 range|value is \\\[1, 2]" }
      48    }
      49  }
      50  
      51  WRONLY (3, 1) void
      52  wr3_1 (int, int, void*);        // { dg-message "in a call to function 'wr3_1' declared with attribute 'access \\\(write_only, 3, 1\\\)" }
      53  
      54  void test_wr3_1 (void)
      55  {
      56    {
      57      void *null = 0;
      58      void *p = &null;
      59  
      60      wr3_1 (SR (0, 1), 0, null);
      61      wr3_1 (SR (1, 1), 0, p);
      62    }
      63  
      64    void *null = 0;
      65  
      66    wr3_1 (SR (1, 2), 1, null);   // { dg-warning "argument 3 is null but the corresponding size argument 1 range|value is \\\[1, 2]" }
      67  }
      68  
      69  
      70  WRONLY (2, 1) void
      71  wr2_1 (int, void*);
      72  
      73  void test_wrd2_1 (int n)
      74  {
      75    wr2_1 (0, 0);
      76    wr2_1 (SR (-1, 1), 0);
      77    wr2_1 (SR (0, 1), 0);
      78    wr2_1 (SR (1, 2), 0);         // { dg-warning "argument 2 is null but the corresponding size argument 1 range|value is \\\[1, 2]" }
      79  
      80    /* This should probably be diagnosed but to avoid false positives
      81       caused by jump threading and such it would have to be done
      82       earlier than it is now.  */
      83    wr2_1 (n, 0);                 // { dg-warning "argument 2 is null" "unimplemented" { xfail *-*-* } }
      84  }
      85  
      86  
      87  /* Exercise pointer to an incomplete type other than void.  */
      88  
      89  struct Incomplete;
      90  extern struct Incomplete inc;
      91  
      92  extern char ax[];
      93  
      94  WRONLY (1, 2) void
      95  wr1_2_inc (struct Incomplete*, unsigned);
      96  
      97  void test_wr1_2_inc (struct Incomplete *pinc, unsigned n)
      98  {
      99    wr1_2_inc (0, 0);
     100    wr1_2_inc (0, 1);         // { dg-warning "argument 1 is null but the corresponding size argument 2 value is 1" }
     101  
     102    wr1_2_inc (pinc, 1);
     103    wr1_2_inc (&inc, 1);
     104  
     105    wr1_2_inc (pinc, 123);
     106    wr1_2_inc (&inc, 456);
     107  
     108    char a3[3];
     109    pinc = (struct Incomplete*)a3;
     110    wr1_2_inc (pinc, SR (3, 4));
     111    wr1_2_inc (pinc, SR (4, 5));
     112    // { dg-warning "'wr1_2_inc' writing between 4 and 5 bytes into a region of size 3" "small buffer cast to incomplete" { target *-*-* } .-1 }
     113  
     114    pinc = (struct Incomplete*)ax;
     115    wr1_2_inc (pinc, SR (123, 456));
     116  
     117    char vla[n];
     118    pinc = (struct Incomplete*)vla;
     119    wr1_2_inc (pinc, SR (345, 456));
     120  }
     121  
     122  
     123  RDONLY (1, 3) WRONLY (2, 4) void
     124  rd1_3_wr2_4 (const void*, void*, int, int);
     125  
     126  void test_rd1_3_wr2_4 (const void *s, void *d, int n1, int n2)
     127  {
     128    rd1_3_wr2_4 (s, d, 1, 2);
     129    rd1_3_wr2_4 (s, d, 123, 456);
     130    rd1_3_wr2_4 (s, d, INT_MAX, INT_MAX);
     131    rd1_3_wr2_4 (s, d, -1, 2);    // { dg-warning "argument 3 value -1 is negative" }
     132  
     133    const int ir_min_m1 = SR (INT_MIN, -1);
     134    rd1_3_wr2_4 (s, d, ir_min_m1, 2);   // { dg-warning "argument 3 range|value \\\[-\[0-9\]+, -1] is negative" }
     135  
     136    rd1_3_wr2_4 (s, d, SR (-1, 0), 2);
     137    rd1_3_wr2_4 (s, d, SR (INT_MIN, INT_MAX), 2);
     138  
     139    rd1_3_wr2_4 (s, d, n1, n2);
     140  
     141  
     142    const char s11[11] = "0123456789";
     143  
     144    rd1_3_wr2_4 (s11, d, 11, n2);
     145    rd1_3_wr2_4 (s11, d, 12, n2);   // { dg-warning "'rd1_3_wr2_4' reading 12 bytes from a region of size 11" }
     146  
     147    rd1_3_wr2_4 (s11, d, SR (0, 11), n2);
     148    rd1_3_wr2_4 (s11, d, SR (0, 12), n2);
     149    rd1_3_wr2_4 (s11, d, SR (11, 12), n2);
     150    rd1_3_wr2_4 (s11, d, SR (11, INT_MAX), n2);
     151    rd1_3_wr2_4 (s11, d, SR (12, 13), n2);  // { dg-warning "'rd1_3_wr2_4' reading between 12 and 13 bytes from a region of size 11" }
     152  
     153    char d4[4];
     154    rd1_3_wr2_4 (s, d4, n1, 4);
     155    rd1_3_wr2_4 (s, d4, n1, 5);     // { dg-warning "'rd1_3_wr2_4' writing 5 bytes into a region of size 4" }
     156  
     157    rd1_3_wr2_4 (s11, d4, SR (12, 13), SR (5, 6));
     158    // { dg-warning "'rd1_3_wr2_4' reading between 12 and 13 bytes from a region of size 11" "read" { target *-*-* } .-1 }
     159    // { dg-warning "'rd1_3_wr2_4' writing between 5 and 6 bytes into a region of size 4" "read" { target *-*-* } .-2 }
     160  }
     161  
     162  
     163  /* Verify that function pointers are handled.  */
     164  
     165  RDONLY (1) void (*pfrd1)(const void*, const void*);
     166  
     167  void test_pfrd1 (void)
     168  {
     169    pfrd1 ("" + SR (0, 9), "" + SR (1, 9));
     170    pfrd1 ("" + SR (1, 2), "");   // { dg-warning "reading 1 byte from a region of size 0" }
     171  }
     172  
     173  
     174  WRONLY (4, 3) void (*pfwr4_3)(int, const char*, int, int32_t*);
     175  
     176  void test_pfwr4_3 (void)
     177  {
     178    int32_t i;
     179    pfwr4_3 (3, "", 0, &i + SR (0, 9));
     180    pfwr4_3 (5, "", 1, &i + SR (1, 2));   // { dg-warning "writing 4 bytes into a region of size 0" }
     181  }