1  /* { dg-additional-options "-Wno-unused-but-set-variable" } */
       2  /* { dg-require-effective-target alloca } */
       3  
       4  #include <string.h>
       5  #include <stdlib.h>
       6  #include <stdint.h>
       7  
       8  /* Tests with symbolic values.  */
       9  
      10  void test1 (size_t size)
      11  {
      12    char *buf = __builtin_malloc (size);
      13    if (!buf) return;
      14  
      15    buf[size] = '\0'; /* { dg-warning "heap-based buffer overflow" } */
      16    __builtin_free (buf);
      17  }
      18  
      19  void test2 (size_t size)
      20  {
      21    char *buf = __builtin_malloc (size);
      22    if (!buf) return;
      23  
      24    buf[size + 1] = '\0'; /* { dg-warning "heap-based buffer overflow" } */
      25    __builtin_free (buf);
      26  }
      27  
      28  void test3 (size_t size, size_t op)
      29  {
      30    char *buf = __builtin_malloc (size);
      31    if (!buf) return;
      32  
      33    buf[size + op] = '\0'; /* { dg-warning "heap-based buffer overflow" } */
      34    __builtin_free (buf);
      35  }
      36  
      37  void test4 (size_t size, unsigned short s)
      38  {
      39    char *buf = __builtin_alloca (size);
      40    buf[size + s] = '\0'; /* { dg-warning "stack-based buffer overflow" } */
      41  }
      42  
      43  void test5 (size_t size)
      44  {
      45    int32_t *buf = __builtin_alloca (4 * size);
      46    buf[size] = 42; /* { dg-warning "stack-based buffer overflow" } */
      47  }
      48  
      49  void test6 (size_t size)
      50  {
      51    int32_t *buf = __builtin_alloca (4 * size);
      52    memset (buf, 0, 4 * size);
      53    int32_t last = *(buf + 4 * size); /* { dg-warning "stack-based buffer over-read" } */
      54  }
      55  
      56  void test7 (size_t size)
      57  {
      58    int32_t *buf = __builtin_alloca (4 * size + 3); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */
      59    buf[size] = 42; /* { dg-warning "stack-based buffer overflow" } */
      60  }
      61  
      62  /* Test where the offset itself is not out-of-bounds
      63     but multiple bytes are read.  */
      64  
      65  void test8 (size_t size, size_t offset)
      66  {
      67    char src[size];
      68    char dst[size];
      69    memcpy (dst, src, size + offset); /* { dg-line test8 } */
      70    /* { dg-warning "over-read" "warning" { target *-*-* } test8 } */
      71    /* { dg-warning "use of uninitialized value" "warning" { target *-*-* } test8 } */
      72    /* { dg-warning "overflow" "warning" { target *-*-* } test8 } */
      73  }
      74  
      75  void test9 (size_t size, size_t offset)
      76  {
      77    int32_t src[size];
      78    int32_t dst[size];
      79    memcpy (dst, src, 4 * size + 1); /* { dg-line test9 } */
      80    /* { dg-warning "over-read" "warning" { target *-*-* } test9 } */
      81    /* { dg-warning "use of uninitialized value" "warning" { target *-*-* } test9 } */
      82    /* { dg-warning "overflow" "warning" { target *-*-* } test9 } */
      83  }
      84  
      85  /* Test for no false-positives.  */
      86  
      87  void test10 (size_t size)
      88  {
      89    int32_t buf[4 * size];
      90    /* 4 * size is smaller than 4 * 4 * size.  */
      91    buf[size] = 42;
      92  }
      93  
      94  void test11 (size_t size)
      95  {
      96    int32_t *buf = __builtin_alloca (4 * size + 5); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */
      97    buf[size] = 42;
      98  }
      99  
     100  void test12 (size_t size, size_t offset)
     101  {
     102    int buf[size];
     103    buf[offset] = 42;
     104  }
     105  
     106  void test13 (size_t size, int offset)
     107  {
     108    int buf[size];
     109    /* We don't know whether offset is positive or not.  */
     110    buf[size + offset] = 42;
     111  }
     112  
     113  void test14 (size_t size, size_t offset, size_t offset2)
     114  {
     115    int buf[size];
     116    /* We don't know whether offset > offset2.  */
     117    buf[size + offset - offset2] = 42;
     118  }
     119  
     120  void test15 (size_t a, size_t b)
     121  {
     122    int buf[a * b];
     123    /* We can't reason about a*b < a+b either.  */
     124    buf[a + b] = 42;
     125  }
     126  
     127  /* Misc.  */
     128  
     129  char *test98 (const char *x, const char *y)
     130  {
     131    size_t len_x = __builtin_strlen (x);
     132    size_t len_y = __builtin_strlen (y);
     133    size_t sz = len_x + len_y + 1;
     134    char *result = __builtin_malloc (sz);
     135    if (!result)
     136      return NULL;
     137    __builtin_memcpy (result, x, len_x);
     138    __builtin_memcpy (result + len_x, y, len_y);
     139    result[len_x + len_y] = '\0';
     140    return result;
     141  }
     142  
     143  char *test99 (const char *x, const char *y)
     144  {
     145    size_t len_x = __builtin_strlen (x);
     146    size_t len_y = __builtin_strlen (y);
     147    /* BUG (root cause): forgot to add 1 for terminator.  */
     148    size_t sz = len_x + len_y;
     149    char *result = __builtin_malloc (sz);
     150    if (!result)
     151      return NULL;
     152    __builtin_memcpy (result, x, len_x);
     153    __builtin_memcpy (result + len_x, y, len_y);
     154    /* BUG (symptom): off-by-one out-of-bounds write to heap.  */
     155    result[len_x + len_y] = '\0'; /* { dg-warning "heap-based buffer overflow" } */
     156    return result;
     157  }