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