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
same_size_and_offset_idx_cst(void)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] to an object with size between 2 and 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, 4] to an object with size between 2 and 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] to an object with size between 3 and 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, 5] to an object with size between 3 and 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
different_size_and_offset_idx_cst(void)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] to an object with size between 2 and 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] to an object with size between 2 and 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, 4] to an object with size between 2 and 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, -1] to an object with size between 3 and 4 allocated by 'alloc1'" "note" { target *-*-* } .-1 }
104
105 /* The offsets -5 and -4 are both necessarily invalid even if the sum
106 (i - 5) and (i - 4) are (or could be) in bounds because they imply
107 that the intermediate offset (p + i) is out of bounds. */
108 T (n, i, -5); // { dg-warning "" "intermediate offset" { xfail *-*-* } }
109 T (n, i, -4); // { dg-warning "" "intermediate offset" { xfail *-*-* } }
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, 7] to an object with size between 3 and 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. */
different_size_and_offset_idx_var(void)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 /* The warning is issued below but the offset and the size in
137 the note are wrong. See the FIXME in compute_objsize(). */
138 T (n, i, SR ( 3, 4)); // { dg-warning "\\\[-Wstringop-overflow" }
139 // { dg-message "at offset 4 to an object with size between 3 and 4 allocated by 'alloc1'" "pr92940 note: offset addition" { xfail *-*-* } .-1 }
140 // { dg-message "at offset . to an object with size . allocated by 'alloc1'" "note: offset addition" { target *-*-* } .-2 }
141 }
142 }
143
144
ptr_add_2(int n,int i0,int i1)145 void ptr_add_2 (int n, int i0, int i1)
146 {
147 if (n < 1 || 2 < n) n = 2;
148
149 if (i0 < 0 || 1 < i0) i0 = 0;
150 if (i1 < 1 || 2 < i1) i1 = 1;
151
152 char *p = (char*)__builtin_malloc (n);
153 char *q = p;
154
155 q += i0;
156 q[0] = 0; // p[0]
157 q += i1;
158 q[0] = 1; // p[1]
159 q[1] = 2; // p[2] // { dg-warning "\\\[-Wstringop-overflow" }
160
161 sink (p, q);
162 }
163
ptr_add_3(int n,int i0,int i1,int i2)164 void ptr_add_3 (int n, int i0, int i1, int i2)
165 {
166 if (n < 3 || 4 < n) n = 3;
167
168 if (i0 < 0 || 1 < i0) i0 = 0;
169 if (i1 < 1 || 2 < i1) i1 = 1;
170 if (i2 < 2 || 3 < i2) i2 = 2;
171
172 char *p = (char*)__builtin_malloc (n);
173 char *q = p;
174
175 q += i0;
176 q[0] = 0; // p[0]
177 q += i1;
178 q[0] = 1; // p[1]
179 q[1] = 2; // p[2]
180 q += i2;
181 q[0] = 3; // p[3]
182 q[1] = 4; // p[4] // { dg-warning "\\\[-Wstringop-overflow" }
183
184 sink (p, q);
185 }
186
ptr_add_4(int n,int i0,int i1,int i2,int i3)187 void ptr_add_4 (int n, int i0, int i1, int i2, int i3)
188 {
189 if (n < 7 || 8 < n) n = 7;
190
191 if (i0 < 0 || 1 < i0) i0 = 0;
192 if (i1 < 1 || 2 < i1) i1 = 1;
193 if (i2 < 2 || 3 < i2) i2 = 2;
194 if (i3 < 3 || 4 < i3) i3 = 3;
195
196 char *p = (char*)__builtin_malloc (n);
197 char *q = p;
198
199 q += i0;
200 q[0] = 0; // p[0]
201 q += i1;
202 q[0] = 1; // p[1]
203 q[1] = 2; // p[2]
204 q += i2;
205 q[0] = 3; // p[3]
206 q[1] = 4; // p[4]
207 q[2] = 5; // p[5]
208 q += i3;
209 q[0] = 6; // p[6]
210 q[1] = 7; // p[7]
211 q[2] = 8; // p[8] // { dg-warning "\\\[-Wstringop-overflow" }
212
213 sink (p, q);
214 }
215
ptr_sub_from_end(int n,int i0,int i1,int i2,int i3)216 void ptr_sub_from_end (int n, int i0, int i1, int i2, int i3)
217 {
218 if (n < 1 || 2 < n) n = 2;
219
220 char *p = (char*)__builtin_malloc (n);
221 char *q = p;
222
223 // The following isn't diagnosed due to a bug/limitation.
224 q += n; // N=1 N=2
225 q[-1] = 0; // p[0] p[1]
226 q[-2] = 1; // p[-1] p[0]
227 q[-3] = 2; // p[-2] p[-1] // { dg-warning "\\\[-Wstringop-overflow" "pr92939: negative offset from end" { xfail *-*-* } }
228
229 /* The following isn't diagnosed because the warning doesn't recognize
230 the index below as necessarily having the same value as the size
231 argument to malloc. All it considers is the range. */
232 q[0] = 2; // { dg-warning "\\\[-Wstringop-overflow" "pr92937: store just past the end" { xfail *-*-* } }
233 q[1] = 3; // { dg-warning "\\\[-Wstringop-overflow" }
234
235 sink (p, q);
236 }
237