(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.dg/
analyzer/
taint-read-offset-1.c
       1  // TODO: remove need for this option:
       2  /* { dg-additional-options "-fanalyzer-checker=taint" } */
       3  
       4  #include <stdio.h>
       5  #include <stdlib.h>
       6  #include <string.h>
       7  
       8  struct foo
       9  {
      10    ssize_t offset;
      11  };
      12  
      13  char *p;
      14  
      15  char test_1(FILE *f)
      16  {
      17    struct foo tmp;
      18  
      19    if (1 == fread(&tmp, sizeof(tmp), 1, f)) { /* { dg-message "\\(\[0-9\]+\\) 'tmp' gets an unchecked value here" "event: tmp gets unchecked value" { xfail *-*-* } } */
      20                                               /* { dg-message "\\(\[0-9\]+\\) following 'true' branch\\.\\.\\." "event: following true branch" { target *-*-* } .-1 } */
      21      return *(p + tmp.offset); // { dg-warning "use of attacker-controlled value 'tmp.offset' as offset without bounds checking" "warning" } */
      22      /* { dg-message "\\(\[0-9\]+\\) \\.\\.\\.to here" "event: to here" { target *-*-* } .-1 } */
      23      /* { dg-message "\\(\[0-9\]+\\) 'tmp.offset' has an unchecked value here \\(from 'tmp'\\)" "event: tmp.offset has an unchecked value" { xfail *-*-* } .-2 } */
      24      /* { dg-message "\\(\[0-9\]+\\) use of attacker-controlled value 'tmp.offset' as offset without bounds checking" "final event" { target *-*-* } .-3 } */
      25      
      26      // TOOD: better messages for state changes
      27    }
      28    return 0;
      29  }
      30  
      31  char test_2(struct foo *f)
      32  {
      33    /* not a bug: the data is not known to be tainted: */
      34    return *(p + f->offset);
      35  }
      36  
      37  char test_3(FILE *f)
      38  {
      39    struct foo tmp;
      40  
      41    if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
      42      if (tmp.offset >= 0 && tmp.offset < 256) {
      43        /* not a bug: the access is guarded by upper and lower bounds: */
      44        return *(p + tmp.offset);
      45      }
      46    }
      47    return 0;
      48  }
      49  
      50  char test_4(FILE *f)
      51  {
      52    struct foo tmp;
      53  
      54    if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
      55      if (tmp.offset >= 0) { /* { dg-message "'tmp.offset' has an unchecked value here \\(from 'tmp'\\)" "event: tmp.offset has an unchecked value" { xfail *-*-* } } */
      56        /* { dg-message "'tmp.offset' has its lower bound checked here" "event: lower bound checked" { xfail *-*-* } .-1 } */
      57        return *(p + tmp.offset); /* { dg-warning "use of attacker-controlled value 'tmp.offset' as offset without upper-bounds checking" "warning" } */
      58      }
      59    }
      60    return 0;
      61  }
      62  
      63  char test_5(FILE *f)
      64  {
      65    struct foo tmp;
      66  
      67    if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
      68      if (tmp.offset < 256) { /* { dg-message "'tmp.offset' has an unchecked value here \\(from 'tmp'\\)" "event: tmp.offset has an unchecked value" { xfail *-*-* } } */
      69        /* { dg-message "'tmp.offset' has its upper bound checked here" "event: upper bound checked" { xfail *-*-* } .-1 } */
      70        return *(p + tmp.offset); /* { dg-warning "use of attacker-controlled value 'tmp.offset' as offset without lower-bounds checking" "warning" } */
      71      }
      72    }
      73    return 0;
      74  }
      75  
      76  /* unsigned types have a natural lower bound of 0 */
      77  struct bar
      78  {
      79    size_t offset;
      80  };
      81  
      82  char test_6(FILE *f)
      83  {
      84    struct bar tmp;
      85  
      86    if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
      87      return *(p + tmp.offset); /* { dg-warning "use of attacker-controlled value 'tmp.offset' as offset without upper-bounds checking" } */
      88    }
      89    return 0;
      90  }
      91  
      92  char test_7(FILE *f)
      93  {
      94    struct bar tmp;
      95  
      96    if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
      97      if (tmp.offset >= 0) {
      98        return *(p + tmp.offset); /* { dg-warning "use of attacker-controlled value 'tmp.offset' as offset without upper-bounds checking" } */
      99      }
     100    }
     101    return 0;
     102  }
     103  
     104  char test_8(FILE *f)
     105  {
     106    struct bar tmp;
     107  
     108    if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
     109      if (tmp.offset < 256) {
     110        /* not a bug: has an upper bound, and an implicit lower bound: */
     111        return *(p + tmp.offset);
     112      }
     113    }
     114    return 0;
     115  }
     116  
     117  char test_9(FILE *f)
     118  {
     119    struct foo tmp;
     120  
     121    if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
     122      if (tmp.offset == 42) {
     123        /* not a bug: tmp.offset compared against a specific value: */
     124        return *(p + tmp.offset); /* { dg-bogus "attacker-controlled" "" { xfail *-*-* } } */
     125      }
     126    }
     127    return 0;
     128  }