1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
|
/* Test for MIN and MAX expressions involving pointers.
{ dg-do compile }
{ dg-options "-O2 -Wall -Wno-array-bounds -ftrack-macro-expansion=0" } */
#include "range.h"
#define INT_MAX __INT_MAX__
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define MAX(x, y) ((x) < (y) ? (y) : (x))
typedef __SIZE_TYPE__ size_t;
void* memset (void*, int, size_t);
#define memset(...) sink (memset (__VA_ARGS__))
void sink (void*, ...);
volatile int cond, vi;
char* volatile ptr;
void test_min (void)
{
const int i1 = SR (1, INT_MAX);
const int i2 = SR (2, INT_MAX);
{
/* Exercise both pointers pointing to a different unknown object plus
positive constant offset. Since PTR is volatile P1 and P2 cannot
normally be considered to point to the same object. It can only
be inferred from the MIN expression. */
char *p1 = ptr + 1;
char *p2 = ptr + 2;
char *q = MIN (p1, p2);
memset (q, 0, 1);
memset (q, 0, 2);
memset (q, 0, INT_MAX);
// { dg-warning "writing 2147483647 bytes into a region of size 2147483646" "ilp32" { target ilp32 } .-1 }
memset (q, 0, DIFF_MAX - 2);
memset (q, 0, DIFF_MAX);
// { dg-warning "writing 2147483647 bytes into a region of size 2147483646" "ilp32" { target ilp32 } .-1 }
// { dg-warning "writing 9223372036854775807 bytes into a region of size 9223372036854775806" "lp64" { target lp64 } .-2 }
}
{
/* Exercise both pointers pointing to a different unknown object plus
variable offset. */
char *p1 = ptr + vi;
char *p2 = ptr + vi;
char *q = MIN (p1, p2);
memset (q, 0, 1);
memset (q, 0, 2);
memset (q, 0, INT_MAX);
}
{
/* Exercise both pointers pointing to the same object plus constant
offset. */
char a2[2]; // { dg-message "at offset 1 into destination object 'a2' of size 2" "note" }
char *p1 = a2 + 1;
char *p2 = a2 + 2;
char *q = MIN (p1, p2);
memset (q, 0, 1);
memset (q, 0, 2); // { dg-warning "writing 2 bytes into a region of size 1 " }
}
{
/* Exercise both pointers pointing to the same object plus offset
in a known range. */
char a3[3]; // { dg-message "at offset \\\[1, 3] into destination object 'a3'" "note" }
char *pi = a3 + i1;
char *pj = a3 + i2;
char *q = MIN (pi, pj);
memset (q, 0, 1);
memset (q, 0, 2);
memset (q, 0, 3); // { dg-warning "writing 3 bytes into a region of size 2 " }
}
{
/* Exercise both pointers pointing to the same object plus variable
offset. Verify that no offset is mentioned in the note (since
its unknown, printing its full range is unnecessary). */
char a4[4]; // { dg-message ": destination object 'a4'" "note" }
char *pi = a4 + vi;
char *pj = a4 + vi;
char *q = MIN (pi, pj);
memset (q, 0, 1);
memset (q, 0, 2);
memset (q, 0, 3);
memset (q, 0, 4);
memset (q, 0, 5); // { dg-warning "writing 5 bytes into a region of size 4 " }
}
{
/* Exercise a pointer pointing to a known object with one pointing
to an unknown object. */
char a5[5]; // { dg-message ": destination object 'a5'" "note" }
char *p = ptr;
char *q = MIN (p, a5);
memset (q, 0, 1);
memset (q, 0, 2);
memset (q, 0, 5);
memset (q, 0, 6); // { dg-warning "writing 6 bytes into a region of size 5 " }
}
{
/* Exercise a pointer pointing to a known object plus constant offset
with one pointing to an unknown object. */
char a6[6]; // { dg-message "(at offset 1 into )?destination object 'a6'" "note" }
char *p1 = ptr;
char *p2 = a6 + 1;
char *q = MIN (p1, p2);
memset (q, 0, 1);
memset (q, 0, 2);
memset (q, 0, 6);
memset (q, 0, 7); // { dg-warning "writing 7 bytes into a region of size 6 " }
}
{
/* Exercise a pointer pointing to a known object with one pointing
to an unknown object plus constant offset. */
char a7[7]; // { dg-message ": destination object 'a7'" "note" }
char *p1 = a7;
char *p2 = ptr + 1;
/* Since p1 points to a7[0] it must be less than any pointer to a7
plus positive offset, and so Q == P1. */
char *q = MIN (p1, p2);
memset (q, 0, 1);
memset (q, 0, 2);
memset (q, 0, 3);
memset (q, 0, 7);
memset (q, 0, 8); // { dg-warning "writing 8 bytes into a region of size 7 " }
}
{
/* Exercise a pointer pointing to a known object plus constant offset
with one pointing to an unknown object plus a different constant
offset. */
char a8[8]; // { dg-message "at offset 1 into destination object 'a8'" "note" }
char *p1 = a8 + 1;
char *p2 = ptr + 2;
/* Since P1 points to A8[1] it must be less than or equal to any
pointer to A8 plus positive offset. Either way, Q must point
to A8[1]. */
char *q = MIN (p1, p2);
memset (q, 0, 1);
memset (q, 0, 2);
memset (q, 0, 7);
memset (q, 0, 8); // { dg-warning "writing 8 bytes into a region of size 7 " }
}
{
/* Same as above but with larger offsets. */
char a9[9]; // { dg-message "at offset 3 into destination object 'a9'" "note" }
char *p1 = a9 + 3;
char *p2 = ptr + 4;
/* Since P1 points to A9[3] it must be less than or equal to any
pointer anywhere into A9 plus 4, so Q must point to A9[3]. */
char *q = MIN (p1, p2);
memset (q, 0, 1);
memset (q, 0, 2);
memset (q, 0, 6);
memset (q, 0, 7); // { dg-warning "writing 7 bytes into a region of size 6 " }
}
{
/* Same as above but with the offsets reversed. */
char a10[10]; // { dg-message "at offset 5 into destination object 'a10'" "note" }
char *p1 = a10 + 10;
char *p2 = ptr + 5;
/* Since P1 points just past the end of A10 it could be either less
or equal to another pointer anywhere into A10 plus 3 because
the other pointer itself could start at a non-zero offset that's
not reflected in the determined offset). */
char *q = MIN (p1, p2);
memset (q, 0, 1);
memset (q, 0, 2);
memset (q, 0, 5);
memset (q, 0, 6); // { dg-warning "writing 6 bytes into a region of size 5 " }
}
{
char a3[3]; // { dg-message ": destination object 'a3'" "note" }
char *p1 = ptr;
char *p2 = a3 + i1;
char *q = MIN (p1, p2);
memset (q, 0, 1);
memset (q, 0, 2);
memset (q, 0, 3);
memset (q, 0, 4); // { dg-warning "writing 4 bytes into a region of size 3 " }
}
}
void test_max (void)
{
const int i1 = SR (1, INT_MAX);
const int i2 = SR (2, INT_MAX);
{
/* Exercise both pointers pointing to the same object plus constant
offset. */
char a2[2];
char *pi = a2 + 1;
char *pj = a2 + 2;
char *q = MAX (pi, pj);
memset (q, 0, 1); // { dg-warning "writing 1 byte into a region of size 0 " }
memset (q, 0, 2); // { dg-warning "writing 2 bytes into a region of size 0 " }
}
{
/* Exercise both pointers pointing to the same object plus offset
in a known range. */
char a3[3]; // { dg-message "at offset \\\[1, 3] into destination object 'a3'" "note" }
char *pi = a3 + i1;
char *pj = a3 + i2;
char *q = MAX (pi, pj);
memset (q, 0, 1);
memset (q, 0, 2);
memset (q, 0, 3); // { dg-warning "writing 3 bytes into a region of size 2 " }
}
{
/* Exercise both pointers pointing to the same object plus variable
offset. Verify that no offset is mentioned in the note (since
its unknown, printing its full range is unnecessary). */
char a4[4]; // { dg-message ": destination object 'a4'" "note" }
char *pi = a4 + vi;
char *pj = a4 + vi;
char *q = MAX (pi, pj);
memset (q, 0, 1);
memset (q, 0, 2);
memset (q, 0, 3);
memset (q, 0, 4);
memset (q, 0, 5); // { dg-warning "writing 5 bytes into a region of size 4 " }
}
{
/* Exercise a pointer pointing to a known object with one pointing
to an unknown object. */
char a5[5]; // { dg-message ": destination object 'a5'" "note" }
char *p = ptr;
char *q = MAX (p, a5);
memset (q, 0, 1);
memset (q, 0, 2);
memset (q, 0, 5);
memset (q, 0, 6); // { dg-warning "writing 6 bytes into a region of size 5 " }
}
{
/* Exercise a pointer pointing to a known object plus constant offset
with one pointing to an unknown object. */
char a6[6]; // { dg-message "at offset 1 into destination object 'a6'" "note" }
char *p1 = ptr;
char *p2 = a6 + 1;
char *q = MAX (p1, p2);
memset (q, 0, 1);
memset (q, 0, 5);
memset (q, 0, 6); // { dg-warning "writing 6 bytes into a region of size 5 " }
memset (q, 0, 7); // { dg-warning "writing 7 bytes into a region of size 5 " }
}
{
/* Exercise a pointer pointing to a known object with one pointing
to an unknown object plus constant offset. */
char a7[7]; // { dg-message "at offset 1 into destination object 'a7'" "note" }
char *p1 = a7;
char *p2 = ptr + 1;
/* Since p1 points to a7[0] it must be less than any pointer to a7
plus positive offset, and so Q == P2. */
char *q = MAX (p1, p2);
memset (q, 0, 1);
memset (q, 0, 6);
memset (q, 0, 7); // { dg-warning "writing 7 bytes into a region of size 6 " }
memset (q, 0, 8); // { dg-warning "writing 8 bytes into a region of size 6 " }
}
{
/* Exercise a pointer pointing to a known object plus constant offset
with one pointing to an unknown object plus a different constant
offset. */
char a8[8]; // { dg-message "at offset 2 into destination object 'a8'" "note" }
char *p1 = a8 + 1;
char *p2 = ptr + 2;
/* Since P1 points to A8[1] it must be less than or equal to any
pointer to A8 plus positive offset. Either way, Q must point
to A8[2]. */
char *q = MAX (p1, p2);
memset (q, 0, 1);
memset (q, 0, 6);
memset (q, 0, 7); // { dg-warning "writing 7 bytes into a region of size 6 " }
memset (q, 0, 8); // { dg-warning "writing 8 bytes into a region of size 6 " }
}
{
/* Same as above but with larger offsets. */
char a9[9]; // { dg-message "at offset 4 into destination object 'a9'" "note" }
char *p1 = a9 + 3;
char *p2 = ptr + 4;
/* Since P1 points to A9[3] it must be less than or equal to any
pointer anywhere into A9 plus 4, so Q must point to A9[4]. */
char *q = MAX (p1, p2);
memset (q, 0, 1);
memset (q, 0, 2);
memset (q, 0, 5);
memset (q, 0, 6); // { dg-warning "writing 6 bytes into a region of size 5 " }
}
{
/* Same as above but with the offsets reversed. */
char a10[10]; // { dg-message "at offset 10 into destination object 'a10'" "note" }
char *p1 = a10 + 10;
char *p2 = ptr + 5;
/* Since P1 points just past the end of A10 it could be either less
or equal to another pointer anywhere into A10 plus 3 because
the other pointer itself could start at a non-zero offset that's
not reflected in the determaxed offset). */
char *q = MAX (p1, p2);
memset (q, 0, 1); // { dg-warning "writing 1 byte into a region of size 0 " }
}
{
char a11[11]; // { dg-message "at offset \\\[1, 11] into destination object 'a11'" "note" }
char *p1 = ptr;
char *p2 = a11 + i1;
char *q = MAX (p1, p2);
memset (q, 0, 1);
memset (q, 0, 2);
memset (q, 0, 10);
memset (q, 0, 11); // { dg-warning "writing 11 bytes into a region of size 10 " }
}
}
|