(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.dg/
builtin-stringop-chk-4.c
       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
      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
      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  
      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" } */
     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 \(bound|size\) between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
     106    memcpy (buf, s, UR (size_max - 1, size_max));  /* { dg-warning "specified \(bound|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 \(bound|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 \(bound|size\) between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
     128    memcpy (d, s, SR (-2, -1));   /* { dg-warning "specified \(bound|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  
     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 \(bound|size\) between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
     191    mempcpy (buf, s, UR (size_max - 1, size_max));  /* { dg-warning "specified \(bound|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 \(bound|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  
     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 \(bound|size\) between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
     217    memset (buf, 0, UR (size_max - 1, size_max));  /* { dg-warning "specified \(bound|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 \(bound|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  
     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 \(bound|size\) between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
     243    bzero (buf, UR (size_max - 1, size_max));  /* { dg-warning "specified \(bound|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 \(bound|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  
     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  
     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  
     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  
     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|size\) 1 exceeds destination size 0" } */
     347    strncat (buf + 5, S (1), 1);   /* { dg-warning "specified \(bound|size\) 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|size\) 5 equals destination size" } */
     354    strncat (buf, S (0), 6);   /* { dg-warning "specified \(bound|size\) 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|size\) 5 equals destination size" } */
     362    strncat (buf, S (1), 6);   /* { dg-warning "specified \(bound|size\) 6 exceeds destination size 5" } */
     363    strncat (buf, S (2), 6);   /* { dg-warning "specified \(bound|size\) 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|size\) 6 exceeds destination size 5" } */
     370    strncat (buf, S (7), 6);   /* { dg-warning "specified \(bound|size\) 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  
     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|size\) 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|size\) 5 equals destination size" } */
     402  
     403    strncat_chk (buf, S (5), 10);   /* { dg-warning "specified \(bound|size\) \[0-9\]+ exceeds destination size 5" } */
     404  
     405    strncat_chk (d, S (5), size_max);   /* { dg-warning "specified \(bound|size\) \[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  
     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 \(bound|size\) \[0-9\]+ exceeds maximum object size" } */
     430    strncpy (buf, S (4), size_max);   /* { dg-warning "specified \(bound|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 \(bound|size\) \[0-9\]+ exceeds maximum object size" } */
     437    strncpy (d, S (4), size_max);   /* { dg-warning "specified \(bound|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  
     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 \(bound|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 \(bound|size\) between \[0-9\]+ and \[0-9\]+ exceeds maximum object size" } */
     504  }