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" } */
6 
7 #define INT_MAX      __INT_MAX__
8 #define PTRDIFF_MAX  __PTRDIFF_MAX__
9 #define SIZE_MAX     __SIZE_MAX__
10 
11 typedef __PTRDIFF_TYPE__ ptrdiff_t;
12 typedef __SIZE_TYPE__    size_t;
13 
14 static const size_t ssize_max = SIZE_MAX / 2;
15 static const size_t size_max = SIZE_MAX;
16 
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;
25 
26 #define memcpy(d, s, n) (memcpy ((d), (s), (n)), sink ((d)))
27 extern void* (memcpy)(void*, const void*, size_t);
28 
29 #define mempcpy(d, s, n) (mempcpy ((d), (s), (n)), sink ((d)))
30 extern void* (mempcpy)(void*, const void*, size_t);
31 
32 #define memset(d, c, n) (memset ((d), (c), (n)), sink ((d)))
33 extern void* (memset)(void*, int, size_t);
34 
35 #define bzero(d, n) (bzero ((d), (n)), sink ((d)))
36 extern void (bzero)(void*, size_t);
37 
38 #define strcat(d, s) (strcat ((d), (s)), sink ((d)))
39 extern char* (strcat)(char*, const char*);
40 
41 #define strncat(d, s, n) (strncat ((d), (s), (n)), sink ((d)))
42 extern char* (strncat)(char*, const char*, size_t);
43 
44 #define strcpy(d, s) (strcpy ((d), (s)), sink ((d)))
45 extern char* (strcpy)(char*, const char*);
46 
47 #define strncpy(d, s, n) (strncpy ((d), (s), (n)), sink ((d)))
48 extern char* (strncpy)(char*, const char*, size_t);
49 
50 void sink (void*);
51 
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);
57 
58 /* Return a random unsigned value between MIN and MAX.  */
59 
60 static inline size_t
unsigned_range(size_t min,size_t max)61 unsigned_range (size_t min, size_t max)
62 {
63   const size_t val = random_unsigned_value ();
64   return val < min || max < val ? min : val;
65 }
66 
67 /* Return a random signed value between MIN and MAX.  */
68 
69 static inline ptrdiff_t
signed_range(ptrdiff_t min,ptrdiff_t max)70 signed_range (ptrdiff_t min, ptrdiff_t max)
71 {
72   const ptrdiff_t val = random_signed_value ();
73   return val < min || max < val ? min : val;
74 }
75 
76 /* For brevity.  */
77 #define UR(min, max)   unsigned_range (min, max)
78 #define SR(min, max)   signed_range (min, max)
79 
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")
85 
86 /* Test memcpy with a number of bytes bounded by a known range.  */
87 
test_memcpy_range(void * d,const void * s)88 void test_memcpy_range (void *d, const void *s)
89 {
90   char buf[5];
91 
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));
97 
98   memcpy (buf, s, UR (6, 7));  /* { dg-warning "writing between 6 and 7 bytes into a region of size 5 overflows the destination" } */
99 
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" } */
101 
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 *-*-* } } */
103 
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" } */
107 
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" } */
112 
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));
119 
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));
126 
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" } */
129 
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);
136 
137   memcpy (buf, s, uchar_val);
138   memcpy (buf, s, ushrt_val);
139   memcpy (buf, s, uint_val);
140   memcpy (buf, s, ulong_val);
141 
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);
146 
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);
151 
152   memcpy (d, s, schar_val);
153   memcpy (d, s, sshrt_val);
154   memcpy (d, s, sint_val);
155   memcpy (d, s, slong_val);
156 
157   memcpy (d, s, uchar_val);
158   memcpy (d, s, ushrt_val);
159   memcpy (d, s, uint_val);
160   memcpy (d, s, ulong_val);
161 
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);
166 
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);
171 }
172 
173 /* Test mempcpy with a number of bytes bounded by a known range.  */
174 
test_mempcpy_range(void * d,const void * s)175 void test_mempcpy_range (void *d, const void *s)
176 {
177   char buf[5];
178 
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));
184 
185   mempcpy (buf, s, UR (6, 7));  /* { dg-warning "writing between 6 and 7 bytes into a region of size 5 overflows the destination" } */
186 
187   mempcpy (buf, s, UR (6, 7));  /* { dg-warning "writing between 6 and 7 bytes into a region of size 5 overflows the destination" } */
188 
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" } */
192 
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" } */
197 }
198 
199 /* Test memset with a number of bytes bounded by a known range.  */
200 
test_memset_range(void * d)201 void test_memset_range (void *d)
202 {
203   char buf[5];
204 
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));
210 
211   memset (buf, 0, UR (6, 7));  /* { dg-warning "writing between 6 and 7 bytes into a region of size 5 overflows the destination" } */
212 
213   memset (buf, 0, UR (6, 7));  /* { dg-warning "writing between 6 and 7 bytes into a region of size 5 overflows the destination" } */
214 
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" } */
218 
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" } */
223 }
224 
225 /* Test bzero with a number of bytes bounded by a known range.  */
226 
test_bzero_range(void * d)227 void test_bzero_range (void *d)
228 {
229   char buf[5];
230 
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));
236 
237   bzero (buf, UR (6, 7));  /* { dg-warning "writing between 6 and 7 bytes into a region of size 5 overflows the destination" } */
238 
239   bzero (buf, UR (6, 7));  /* { dg-warning "writing between 6 and 7 bytes into a region of size 5 overflows the destination" } */
240 
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" } */
244 
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" } */
249 }
250 
251 /* Test strcat with an argument referencing a non-constant string of
252    lengths in a known range.  */
253 
test_strcat_range(void)254 void test_strcat_range (void)
255 {
256   char buf[5] = "";
257 
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 " } */
264 
265   {
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 *-*-* } } */
271   }
272 }
273 
274 /* Verify that strcpy with an unknown source string doesn't cause
275    warnings unless the destination has zero size.  */
276 
test_strcpy(const char * src)277 void test_strcpy (const char *src)
278 {
279   struct A { char a[2]; char b[3]; } a;
280 
281   strcpy (a.a, src);
282   strcpy (a.a + 1, src);
283 
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 *-*-* } } */
300 
301   /* This does work.  */
302   strcpy (a.a + 5, src);    /* { dg-warning "writing 1 or more bytes into a region of size 0 " } */
303 
304   /* As does this.  */
305   strcpy (a.a + 17, src);    /* { dg-warning "writing 1 or more bytes into a region of size 0 " } */
306 }
307 
308 /* Test strcpy with a non-constant source string of length in a known
309    range.  */
310 
test_strcpy_range(void)311 void test_strcpy_range (void)
312 {
313   char buf[5];
314 
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" } */
325 
326   strcpy (buf + 5, S (0));   /* { dg-warning "writing between 1 and 11 bytes" } */
327 
328   strcpy (buf + 17, S (0));   /* { dg-warning "writing between 1 and 11 bytes " } */
329 }
330 
331 /* Test strncat with an argument referencing a non-constant string of
332    lengths in a known range.  */
333 
test_strncat_range(void)334 void test_strncat_range (void)
335 {
336   char buf[5] = "";
337 
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);
343 
344   strncat (buf + 5, S (0), 0);
345 
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" } */
348 
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" } */
355 
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" } */
364 
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" } */
371 
372   {
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 *-*-* } } */
378   }
379 }
380 
381 /* Test strncat_chk with an argument referencing a non-constant string
382    of lengths in a known range.  */
383 
test_strncat_chk_range(char * d)384 void test_strncat_chk_range (char *d)
385 {
386   char buf[5] = "";
387 
388 #define strncat_chk(d, s, n) \
389   __builtin___strncat_chk ((d), (s), (n), __builtin_object_size (d, 1));
390 
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" } */
396 
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" } */
402 
403   strncat_chk (buf, S (5), 10);   /* { dg-warning "specified bound \[0-9\]+ exceeds destination size 5" } */
404 
405   strncat_chk (d, S (5), size_max);   /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size " } */
406 }
407 
408 /* Test strncpy with a non-constant source string of length in a known
409    range and a constant number of bytes.  */
410 
test_strncpy_string_range(char * d)411 void test_strncpy_string_range (char *d)
412 {
413   char buf[5];
414 
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 " } */
422 
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 " } */
426 
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" } */
431 
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" } */
438 }
439 
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.  */
442 
test_strncpy_string_count_range(char * dst,const char * src)443 void test_strncpy_string_count_range (char *dst, const char *src)
444 {
445   char buf[5];
446 
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));
458 
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));
470 
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 " } */
474 
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" } */
476 
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 " } */
481 
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 " } */
494 
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));
500 
501   strncpy (dst, S (3), UR (ssize_max, ssize_max + 1));
502 
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" } */
504 }
505