PR middle-end/77357 - strlen of constant strings not folded
[official-gcc.git] / gcc / testsuite / gcc.dg / builtin-stringop-chk-4.c
blobc0110f2eb62aaba5dcb19478582d404cfdcec970
1 /* Test exercising buffer overflow warnings emitted for raw memory and
2 string manipulation builtins involving ranges of sizes and strings
3 of varying lengths. */
4 /* { dg-do compile } */
5 /* { dg-options "-O2 -ftrack-macro-expansion=0" } */
7 #define INT_MAX __INT_MAX__
8 #define PTRDIFF_MAX __PTRDIFF_MAX__
9 #define SIZE_MAX __SIZE_MAX__
11 typedef __PTRDIFF_TYPE__ ptrdiff_t;
12 typedef __SIZE_TYPE__ size_t;
14 static const size_t ssize_max = SIZE_MAX / 2;
15 static const size_t size_max = SIZE_MAX;
17 extern signed char schar_val;
18 extern signed short sshrt_val;
19 extern signed int sint_val;
20 extern signed long slong_val;
21 extern unsigned char uchar_val;
22 extern unsigned short ushrt_val;
23 extern unsigned int uint_val;
24 extern unsigned long ulong_val;
26 #define memcpy(d, s, n) (memcpy ((d), (s), (n)), sink ((d)))
27 extern void* (memcpy)(void*, const void*, size_t);
29 #define mempcpy(d, s, n) (mempcpy ((d), (s), (n)), sink ((d)))
30 extern void* (mempcpy)(void*, const void*, size_t);
32 #define memset(d, c, n) (memset ((d), (c), (n)), sink ((d)))
33 extern void* (memset)(void*, int, size_t);
35 #define bzero(d, n) (bzero ((d), (n)), sink ((d)))
36 extern void (bzero)(void*, size_t);
38 #define strcat(d, s) (strcat ((d), (s)), sink ((d)))
39 extern char* (strcat)(char*, const char*);
41 #define strncat(d, s, n) (strncat ((d), (s), (n)), sink ((d)))
42 extern char* (strncat)(char*, const char*, size_t);
44 #define strcpy(d, s) (strcpy ((d), (s)), sink ((d)))
45 extern char* (strcpy)(char*, const char*);
47 #define strncpy(d, s, n) (strncpy ((d), (s), (n)), sink ((d)))
48 extern char* (strncpy)(char*, const char*, size_t);
50 void sink (void*);
52 /* Function to "generate" a random number each time it's called. Declared
53 (but not defined) and used to prevent GCC from making assumptions about
54 their values based on the variables uses in the tested expressions. */
55 size_t random_unsigned_value (void);
56 ptrdiff_t random_signed_value (void);
58 /* Return a random unsigned value between MIN and MAX. */
60 static inline size_t
61 unsigned_range (size_t min, size_t max)
63 const size_t val = random_unsigned_value ();
64 return val < min || max < val ? min : val;
67 /* Return a random signed value between MIN and MAX. */
69 static inline ptrdiff_t
70 signed_range (ptrdiff_t min, ptrdiff_t max)
72 const ptrdiff_t val = random_signed_value ();
73 return val < min || max < val ? min : val;
76 /* For brevity. */
77 #define UR(min, max) unsigned_range (min, max)
78 #define SR(min, max) signed_range (min, max)
80 /* Return a pointer to constant string whose length is at least MINLEN
81 and at most 10. */
82 #define S(minlen) \
83 (minlen == random_unsigned_value () \
84 ? "0123456789" + 10 - minlen : "0123456789")
86 /* Test memcpy with a number of bytes bounded by a known range. */
88 void test_memcpy_range (void *d, const void *s)
90 char buf[5];
92 memcpy (buf, s, UR (0, 5));
93 memcpy (buf, s, UR (1, 5));
94 memcpy (buf, s, UR (2, 5));
95 memcpy (buf, s, UR (3, 5));
96 memcpy (buf, s, UR (4, 5));
98 memcpy (buf, s, UR (6, 7)); /* { dg-warning "writing between 6 and 7 bytes into a region of size 5 overflows the destination" } */
100 memcpy (buf + 5, s, UR (1, 2)); /* { dg-warning "writing between 1 and 2 bytes into a region of size 0 overflows the destination" } */
102 memcpy (buf + size_max, s, UR (1, 2)); /* { dg-warning "writing between 1 and 2 bytes into a region of size 0 overflows the destination" "excessive pointer offset" { xfail *-*-* } } */
104 memcpy (buf, s, UR (ssize_max, size_max)); /* { dg-warning "writing \[0-9\]+ or more bytes into a region of size 5 overflows the destination" } */
105 memcpy (buf, s, UR (ssize_max + 1, size_max)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
106 memcpy (buf, s, UR (size_max - 1, size_max)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
108 /* Exercise memcpy into a destination of unknown size with excessive
109 number of bytes. */
110 memcpy (d, s, UR (ssize_max, size_max));
111 memcpy (d, s, UR (ssize_max + 1, size_max)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
113 memcpy (buf, s, SR (-1, 1));
114 memcpy (buf, s, SR (-3, 2));
115 memcpy (buf, s, SR (-5, 3));
116 memcpy (buf, s, SR (-7, 4));
117 memcpy (buf, s, SR (-9, 5));
118 memcpy (buf, s, SR (-11, 6));
120 memcpy (d, s, SR (-1, 1));
121 memcpy (d, s, SR (-3, 2));
122 memcpy (d, s, SR (-5, 3));
123 memcpy (d, s, SR (-7, 4));
124 memcpy (d, s, SR (-9, 5));
125 memcpy (d, s, SR (-11, 6));
127 memcpy (buf, s, SR (-2, -1)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
128 memcpy (d, s, SR (-2, -1)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
130 /* Even though the following calls are bounded by the range of N's
131 type they must not cause a warning for obvious reasons. */
132 memcpy (buf, s, schar_val);
133 memcpy (buf, s, sshrt_val);
134 memcpy (buf, s, sint_val);
135 memcpy (buf, s, slong_val);
137 memcpy (buf, s, uchar_val);
138 memcpy (buf, s, ushrt_val);
139 memcpy (buf, s, uint_val);
140 memcpy (buf, s, ulong_val);
142 memcpy (buf, s, schar_val + 1);
143 memcpy (buf, s, sshrt_val + 2);
144 memcpy (buf, s, sint_val + 3);
145 memcpy (buf, s, slong_val + 4);
147 memcpy (d, s, uchar_val + 5);
148 memcpy (d, s, ushrt_val + 6);
149 memcpy (d, s, uint_val + 7);
150 memcpy (d, s, ulong_val + 8);
152 memcpy (d, s, schar_val);
153 memcpy (d, s, sshrt_val);
154 memcpy (d, s, sint_val);
155 memcpy (d, s, slong_val);
157 memcpy (d, s, uchar_val);
158 memcpy (d, s, ushrt_val);
159 memcpy (d, s, uint_val);
160 memcpy (d, s, ulong_val);
162 memcpy (d, s, schar_val + 1);
163 memcpy (d, s, sshrt_val + 2);
164 memcpy (d, s, sint_val + 3);
165 memcpy (d, s, slong_val + 4);
167 memcpy (d, s, uchar_val + 5);
168 memcpy (d, s, ushrt_val + 6);
169 memcpy (d, s, uint_val + 7);
170 memcpy (d, s, ulong_val + 8);
173 /* Test mempcpy with a number of bytes bounded by a known range. */
175 void test_mempcpy_range (void *d, const void *s)
177 char buf[5];
179 mempcpy (buf, s, UR (0, 5));
180 mempcpy (buf, s, UR (1, 5));
181 mempcpy (buf, s, UR (2, 5));
182 mempcpy (buf, s, UR (3, 5));
183 mempcpy (buf, s, UR (4, 5));
185 mempcpy (buf, s, UR (6, 7)); /* { dg-warning "writing between 6 and 7 bytes into a region of size 5 overflows the destination" } */
187 mempcpy (buf, s, UR (6, 7)); /* { dg-warning "writing between 6 and 7 bytes into a region of size 5 overflows the destination" } */
189 mempcpy (buf, s, UR (ssize_max, size_max)); /* { dg-warning "writing \[0-9\]+ or more bytes into a region of size 5 overflows the destination" } */
190 mempcpy (buf, s, UR (ssize_max + 1, size_max)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
191 mempcpy (buf, s, UR (size_max - 1, size_max)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
193 /* Exercise mempcpy into a destination of unknown size with excessive
194 number of bytes. */
195 mempcpy (d, s, UR (ssize_max, size_max));
196 mempcpy (d, s, UR (ssize_max + 1, size_max)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
199 /* Test memset with a number of bytes bounded by a known range. */
201 void test_memset_range (void *d)
203 char buf[5];
205 memset (buf, 0, UR (0, 5));
206 memset (buf, 0, UR (1, 5));
207 memset (buf, 0, UR (2, 5));
208 memset (buf, 0, UR (3, 5));
209 memset (buf, 0, UR (4, 5));
211 memset (buf, 0, UR (6, 7)); /* { dg-warning "writing between 6 and 7 bytes into a region of size 5 overflows the destination" } */
213 memset (buf, 0, UR (6, 7)); /* { dg-warning "writing between 6 and 7 bytes into a region of size 5 overflows the destination" } */
215 memset (buf, 0, UR (ssize_max, size_max)); /* { dg-warning "writing \[0-9\]+ or more bytes into a region of size 5 overflows the destination" } */
216 memset (buf, 0, UR (ssize_max + 1, size_max)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
217 memset (buf, 0, UR (size_max - 1, size_max)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
219 /* Exercise memset into a destination of unknown size with excessive
220 number of bytes. */
221 memset (d, 0, UR (ssize_max, size_max));
222 memset (d, 0, UR (ssize_max + 1, size_max)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
225 /* Test bzero with a number of bytes bounded by a known range. */
227 void test_bzero_range (void *d)
229 char buf[5];
231 bzero (buf, UR (0, 5));
232 bzero (buf, UR (1, 5));
233 bzero (buf, UR (2, 5));
234 bzero (buf, UR (3, 5));
235 bzero (buf, UR (4, 5));
237 bzero (buf, UR (6, 7)); /* { dg-warning "writing between 6 and 7 bytes into a region of size 5 overflows the destination" } */
239 bzero (buf, UR (6, 7)); /* { dg-warning "writing between 6 and 7 bytes into a region of size 5 overflows the destination" } */
241 bzero (buf, UR (ssize_max, size_max)); /* { dg-warning "writing \[0-9\]+ or more bytes into a region of size 5 overflows the destination" } */
242 bzero (buf, UR (ssize_max + 1, size_max)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
243 bzero (buf, UR (size_max - 1, size_max)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
245 /* Exercise bzero into a destination of unknown size with excessive
246 number of bytes. */
247 bzero (d, UR (ssize_max, size_max));
248 bzero (d, UR (ssize_max + 1, size_max)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
251 /* Test strcat with an argument referencing a non-constant string of
252 lengths in a known range. */
254 void test_strcat_range (void)
256 char buf[5] = "";
258 strcat (buf, S (0));
259 strcat (buf, S (1));
260 strcat (buf, S (2));
261 strcat (buf, S (3));
262 strcat (buf, S (4));
263 strcat (buf, S (5)); /* { dg-warning "writing between 6 and 11 bytes into a region of size 5 " } */
266 /* The implementation of the warning isn't smart enough to determine
267 the length of the string in the buffer so it assumes it's empty
268 and issues the warning basically for the same cases as strcat. */
269 char buf2[5] = "12";
270 strcat (buf2, S (4)); /* { dg-warning "writing 5 bytes into a region of size 3" "strcat to a non-empty string" { xfail *-*-* } } */
274 /* Verify that strcpy with an unknown source string doesn't cause
275 warnings unless the destination has zero size. */
277 void test_strcpy (const char *src)
279 struct A { char a[2]; char b[3]; } a;
281 strcpy (a.a, src);
282 strcpy (a.a + 1, src);
284 /* There must be enough room in the destination for the terminating
285 nul, otherwise verify that a warning is issued.
286 The following works as expected with __builtin___strcpy_chk and
287 __builtin_object_size because they see that the offset is from
288 the a.a array. When optimization is enabled, it isn't detected
289 by __bultin_strcpy (when __builtin_object_size isn't called
290 explicitly) because by the time it's seen the offset has been
291 transformed to one from the beginning of the whole object, i.e.,
292 as if it had been written as (char*)&a + 2 . Then the destination
293 size is taken to be the rest of the whole object. It is detected
294 by __builtin_strcpy when optimization is not enabled because then
295 the &a.a + 2 expression is preserved. But without optimization
296 an ordinary call to strcpy isn't transformed to __builtin_strcpy
297 and so it can't be detected here (since the rest of the test
298 relies on optimization). */
299 strcpy (a.a + 2, src); /* { dg-warning "writing at least 1 byte into a region of size 0 " "strcpy into empty substring" { xfail *-*-* } } */
301 /* This does work. */
302 strcpy (a.a + 5, src); /* { dg-warning "writing 1 or more bytes into a region of size 0 " } */
304 /* As does this. */
305 strcpy (a.a + 17, src); /* { dg-warning "writing 1 or more bytes into a region of size 0 " } */
308 /* Test strcpy with a non-constant source string of length in a known
309 range. */
311 void test_strcpy_range (void)
313 char buf[5];
315 strcpy (buf, S (0));
316 strcpy (buf, S (1));
317 strcpy (buf, S (2));
318 strcpy (buf, S (4));
319 strcpy (buf, S (5)); /* { dg-warning "writing between 6 and 11 bytes into a region of size 5 " } */
320 strcpy (buf, S (6)); /* { dg-warning "writing between 7 and 11 bytes" } */
321 strcpy (buf, S (7)); /* { dg-warning "writing between 8 and 11 bytes" } */
322 strcpy (buf, S (8)); /* { dg-warning "writing between 9 and 11 bytes" } */
323 strcpy (buf, S (9)); /* { dg-warning "writing between 10 and 11 bytes" } */
324 strcpy (buf, S (10)); /* { dg-warning "writing 11 bytes" } */
326 strcpy (buf + 5, S (0)); /* { dg-warning "writing between 1 and 11 bytes" } */
328 strcpy (buf + 17, S (0)); /* { dg-warning "writing between 1 and 11 bytes " } */
331 /* Test strncat with an argument referencing a non-constant string of
332 lengths in a known range. */
334 void test_strncat_range (void)
336 char buf[5] = "";
338 strncat (buf, S (0), 0);
339 strncat (buf, S (0), 1);
340 strncat (buf, S (0), 2);
341 strncat (buf, S (0), 3);
342 strncat (buf, S (0), 4);
344 strncat (buf + 5, S (0), 0);
346 strncat (buf + 5, S (0), 1); /* { dg-warning "specified bound 1 exceeds destination size 0" } */
347 strncat (buf + 5, S (1), 1); /* { dg-warning "specified bound 1 exceeds destination size 0" } */
349 /* Strncat always appends a terminating null after copying the N
350 characters so the following triggers a warning pointing out
351 that specifying sizeof(buf) as the upper bound may cause
352 the nul to overflow the destination. */
353 strncat (buf, S (0), 5); /* { dg-warning "specified bound 5 equals destination size" } */
354 strncat (buf, S (0), 6); /* { dg-warning "specified bound 6 exceeds destination size 5" } */
356 strncat (buf, S (1), 0);
357 strncat (buf, S (1), 1);
358 strncat (buf, S (1), 2);
359 strncat (buf, S (1), 3);
360 strncat (buf, S (1), 4);
361 strncat (buf, S (1), 5); /* { dg-warning "specified bound 5 equals destination size" } */
362 strncat (buf, S (1), 6); /* { dg-warning "specified bound 6 exceeds destination size 5" } */
363 strncat (buf, S (2), 6); /* { dg-warning "specified bound 6 exceeds destination size 5" } */
365 /* The following could just as well say "writing 6 bytes into a region
366 of size 5. Either would be correct and probably equally as clear
367 in this case. But when the length of the source string is not known
368 at all then the bound warning seems clearer. */
369 strncat (buf, S (5), 6); /* { dg-warning "specified bound 6 exceeds destination size 5" } */
370 strncat (buf, S (7), 6); /* { dg-warning "specified bound 6 exceeds destination size 5" } */
373 /* The implementation of the warning isn't smart enough to determine
374 the length of the string in the buffer so it assumes it's empty
375 and issues the warning basically for the same cases as strncpy. */
376 char buf2[5] = "12";
377 strncat (buf2, S (4), 4); /* { dg-warning "writing 5 bytes into a region of size 3" "strncat to a non-empty string" { xfail *-*-* } } */
381 /* Test strncat_chk with an argument referencing a non-constant string
382 of lengths in a known range. */
384 void test_strncat_chk_range (char *d)
386 char buf[5] = "";
388 #define strncat_chk(d, s, n) \
389 __builtin___strncat_chk ((d), (s), (n), __builtin_object_size (d, 1));
391 strncat_chk (buf, S (0), 1);
392 strncat_chk (buf, S (0), 2);
393 strncat_chk (buf, S (0), 3);
394 strncat_chk (buf, S (0), 4);
395 strncat_chk (buf, S (0), 5); /* { dg-warning "specified bound 5 equals destination size" } */
397 strncat_chk (buf, S (5), 1);
398 strncat_chk (buf, S (5), 2);
399 strncat_chk (buf, S (5), 3);
400 strncat_chk (buf, S (5), 4);
401 strncat_chk (buf, S (5), 5); /* { dg-warning "specified bound 5 equals destination size" } */
403 strncat_chk (buf, S (5), 10); /* { dg-warning "specified bound \[0-9\]+ exceeds destination size 5" } */
405 strncat_chk (d, S (5), size_max); /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size " } */
408 /* Test strncpy with a non-constant source string of length in a known
409 range and a constant number of bytes. */
411 void test_strncpy_string_range (char *d)
413 char buf[5];
415 strncpy (buf, S (0), 0);
416 strncpy (buf, S (0), 1);
417 strncpy (buf, S (0), 2);
418 strncpy (buf, S (0), 3);
419 strncpy (buf, S (0), 4);
420 strncpy (buf, S (0), 5);
421 strncpy (buf, S (0), 6); /* { dg-warning "writing 6 bytes into a region of size 5 " } */
423 strncpy (buf, S (6), 4);
424 strncpy (buf, S (7), 5);
425 strncpy (buf, S (8), 6); /* { dg-warning "writing 6 bytes into a region of size 5 " } */
427 strncpy (buf, S (1), ssize_max - 1); /* { dg-warning "writing \[0-9\]+ bytes into a region of size 5" } */
428 strncpy (buf, S (2), ssize_max); /* { dg-warning "writing \[0-9\]+ bytes into a region of size 5" } */
429 strncpy (buf, S (3), ssize_max + 1); /* { dg-warning "specified size \[0-9\]+ exceeds maximum object size" } */
430 strncpy (buf, S (4), size_max); /* { dg-warning "specified size \[0-9\]+ exceeds maximum object size" } */
432 /* Exercise strncpy into a destination of unknown size with a valid
433 and invalid constant number of bytes. */
434 strncpy (d, S (1), ssize_max - 1);
435 strncpy (d, S (2), ssize_max);
436 strncpy (d, S (3), ssize_max + 1); /* { dg-warning "specified size \[0-9\]+ exceeds maximum object size" } */
437 strncpy (d, S (4), size_max); /* { dg-warning "specified size \[0-9\]+ exceeds maximum object size" } */
440 /* Test strncpy with a non-constant source string of length in a known
441 range and a non-constant number of bytes also in a known range. */
443 void test_strncpy_string_count_range (char *dst, const char *src)
445 char buf[5];
447 strncpy (buf, S (0), UR (0, 1));
448 strncpy (buf, S (0), UR (0, 2));
449 strncpy (buf, S (0), UR (0, 3));
450 strncpy (buf, S (0), UR (0, 4));
451 strncpy (buf, S (0), UR (0, 5));
452 strncpy (buf, S (0), UR (0, 6));
453 strncpy (buf, S (0), UR (1, 6));
454 strncpy (buf, S (0), UR (2, 6));
455 strncpy (buf, S (0), UR (3, 6));
456 strncpy (buf, S (0), UR (4, 6));
457 strncpy (buf, S (0), UR (5, 6));
459 strncpy (buf, S (9), UR (0, 1));
460 strncpy (buf, S (8), UR (0, 2));
461 strncpy (buf, S (7), UR (0, 3));
462 strncpy (buf, S (6), UR (0, 4));
463 strncpy (buf, S (8), UR (0, 5));
464 strncpy (buf, S (7), UR (0, 6));
465 strncpy (buf, S (6), UR (1, 6));
466 strncpy (buf, S (5), UR (2, 6));
467 strncpy (buf, S (9), UR (3, 6));
468 strncpy (buf, S (8), UR (4, 6));
469 strncpy (buf, S (7), UR (5, 6));
471 strncpy (buf, S (0), UR (6, 7)); /* { dg-warning "writing between 6 and 7 bytes into a region of size 5 " } */
472 strncpy (buf, S (1), UR (7, 8)); /* { dg-warning "writing between 7 and 8 bytes into a region of size 5 " } */
473 strncpy (buf, S (2), UR (ssize_max, ssize_max + 1)); /* { dg-warning "writing \[0-9\]+ or more bytes into a region of size 5 " } */
475 strncpy (buf, S (2), UR (ssize_max + 1, ssize_max + 2)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
477 strncpy (buf + 5, S (0), UR (0, 1));
478 strncpy (buf + 5, S (1), UR (0, 1));
479 strncpy (buf + 5, S (0), UR (1, 2)); /* { dg-warning "writing between 1 and 2 bytes into a region of size 0 " } */
480 strncpy (buf + 5, S (1), UR (1, 2)); /* { dg-warning "writing between 1 and 2 bytes into a region of size 0 " } */
482 strncpy (buf, src, UR (0, 1));
483 strncpy (buf, src, UR (0, 2));
484 strncpy (buf, src, UR (0, 3));
485 strncpy (buf, src, UR (0, 4));
486 strncpy (buf, src, UR (0, 5));
487 strncpy (buf, src, UR (0, 6));
488 strncpy (buf, src, UR (1, 6));
489 strncpy (buf, src, UR (2, 6));
490 strncpy (buf, src, UR (3, 6));
491 strncpy (buf, src, UR (4, 6));
492 strncpy (buf, src, UR (5, 6));
493 strncpy (buf, src, UR (6, 7)); /* { dg-warning "writing between 6 and 7 bytes into a region of size 5 " } */
495 /* Exercise strncpy into a destination of unknown size with a valid
496 and invalid constant number of bytes. */
497 strncpy (dst, S (0), UR (5, 6));
498 strncpy (dst, S (1), UR (6, 7));
499 strncpy (dst, S (2), UR (7, 8));
501 strncpy (dst, S (3), UR (ssize_max, ssize_max + 1));
503 strncpy (dst, S (4), UR (ssize_max + 1, ssize_max + 2)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */