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