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