(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.c-torture/
execute/
builtins/
stpncpy-chk.c
       1  /* Copyright (C) 2004, 2005, 2011  Free Software Foundation.
       2  
       3     Ensure builtin __stpncpy_chk performs correctly.  */
       4  
       5  extern void abort (void);
       6  typedef __SIZE_TYPE__ size_t;
       7  extern size_t strlen(const char *);
       8  extern void *memcpy (void *, const void *, size_t);
       9  extern char *stpncpy (char *, const char *, size_t);
      10  extern int memcmp (const void *, const void *, size_t);
      11  extern int strcmp (const char *, const char *);
      12  extern int strncmp (const char *, const char *, size_t);
      13  extern void *memset (void *, int, size_t);
      14  
      15  #include "chk.h"
      16  
      17  const char s1[] = "123";
      18  char p[32] = "";
      19  char * volatile s2 = "defg";  /* prevent constant propagation to happen when whole program assumptions are made.  */
      20  char * volatile s3 = "FGH";  /* prevent constant propagation to happen when whole program assumptions are made.  */
      21  char *s4;
      22  volatile size_t l1 = 1;  /* prevent constant propagation to happen when whole program assumptions are made.  */
      23  int i;
      24  
      25  void
      26  __attribute__((noinline))
      27  test1 (void)
      28  {
      29    const char *const src = "hello world";
      30    const char *src2;
      31    char dst[64], *dst2;
      32  
      33    chk_calls = 0;
      34  
      35    memset (dst, 0, sizeof (dst));
      36    if (stpncpy (dst, src, 4) != dst+4 || strncmp (dst, src, 4))
      37      abort();
      38  
      39    memset (dst, 0, sizeof (dst));
      40    if (stpncpy (dst+16, src, 4) != dst+20 || strncmp (dst+16, src, 4))
      41      abort();
      42  
      43    memset (dst, 0, sizeof (dst));
      44    if (stpncpy (dst+32, src+5, 4) != dst+36 || strncmp (dst+32, src+5, 4))
      45      abort();
      46  
      47    memset (dst, 0, sizeof (dst));
      48    dst2 = dst;
      49    if (stpncpy (++dst2, src+5, 4) != dst+5 || strncmp (dst2, src+5, 4)
      50        || dst2 != dst+1)
      51      abort();
      52  
      53    memset (dst, 0, sizeof (dst));
      54    if (stpncpy (dst, src, 0) != dst || strcmp (dst, ""))
      55      abort();
      56    
      57    memset (dst, 0, sizeof (dst));
      58    dst2 = dst; src2 = src;
      59    if (stpncpy (++dst2, ++src2, 0) != dst+1 || strcmp (dst2, "")
      60        || dst2 != dst+1 || src2 != src+1)
      61      abort();
      62  
      63    memset (dst, 0, sizeof (dst));
      64    dst2 = dst; src2 = src;
      65    if (stpncpy (++dst2+5, ++src2+5, 0) != dst+6 || strcmp (dst2+5, "")
      66        || dst2 != dst+1 || src2 != src+1)
      67      abort();
      68  
      69    memset (dst, 0, sizeof (dst));
      70    if (stpncpy (dst, src, 12) != dst+11 || strcmp (dst, src))
      71      abort();
      72  
      73    /* Test at least one instance of the __builtin_ style.  We do this
      74       to ensure that it works and that the prototype is correct.  */
      75    memset (dst, 0, sizeof (dst));
      76    if (__builtin_stpncpy (dst, src, 4) != dst+4 || strncmp (dst, src, 4))
      77      abort();
      78  
      79    memset (dst, 0, sizeof (dst));
      80    if (stpncpy (dst, i++ ? "xfoo" + 1 : "bar", 4) != dst+3
      81        || strcmp (dst, "bar")
      82        || i != 1)
      83      abort ();
      84  
      85    /* If return value of stpncpy is ignored, it should be optimized into
      86       stpncpy call.  */
      87    stpncpy_disallowed = 1;
      88    stpncpy (dst + 1, src, 4);
      89    stpncpy_disallowed = 0;
      90    if (strncmp (dst + 1, src, 4))
      91      abort ();
      92  
      93    if (chk_calls)
      94      abort ();
      95  }
      96  
      97  void
      98  __attribute__((noinline))
      99  test2 (void)
     100  {
     101    chk_calls = 0;
     102  
     103    /* No runtime checking should be done here, both destination
     104       and length are unknown.  */
     105    size_t cpy_length = l1 < 4 ? l1 + 1 : 4;
     106    if (stpncpy (s4, "abcd", l1 + 1) != s4 + cpy_length || strncmp (s4, "abcd", cpy_length))
     107      abort ();
     108  
     109    if (chk_calls)
     110      abort ();
     111  }
     112  
     113  /* Test whether compile time checking is done where it should
     114     and so is runtime object size checking.  */
     115  void
     116  __attribute__((noinline))
     117  test3 (void)
     118  {
     119    struct A { char buf1[10]; char buf2[10]; } a;
     120    char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4];
     121    char buf3[20];
     122    int i;
     123    const char *l;
     124    size_t l2;
     125  
     126    /* The following calls should do runtime checking
     127       - source length is not known, but destination is.  
     128       The returned value is checked so that stpncpy calls
     129       are not rewritten to strncpy calls. */
     130    chk_calls = 0;
     131    if (!stpncpy (a.buf1 + 2, s3 + 3, l1))
     132      abort();
     133    if (!stpncpy (r, s3 + 2, l1 + 2))
     134      abort();
     135    r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
     136    if (!stpncpy (r, s2 + 2, l1 + 2))
     137      abort();
     138    if (!stpncpy (r + 2, s3 + 3, l1))
     139      abort();
     140    r = buf3;
     141    for (i = 0; i < 4; ++i)
     142      {
     143        if (i == l1 - 1)
     144  	r = &a.buf1[1];
     145        else if (i == l1)
     146  	r = &a.buf2[7];
     147        else if (i == l1 + 1)
     148  	r = &buf3[5];
     149        else if (i == l1 + 2)
     150  	r = &a.buf1[9];
     151      }
     152    if (!stpncpy (r, s2 + 4, l1))
     153      abort();
     154    if (chk_calls != 5)
     155      abort ();
     156  
     157    /* Following have known destination and known length,
     158       so if optimizing certainly shouldn't result in the checking
     159       variants.  */
     160    chk_calls = 0;
     161    if (!stpncpy (a.buf1 + 2, "", 3))
     162      abort ();
     163    if (!stpncpy (a.buf1 + 2, "", 0))
     164      abort ();
     165    if (!stpncpy (r, "a", 1))
     166      abort ();
     167    if (!stpncpy (r, "a", 3))
     168      abort ();
     169    r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
     170    if (!stpncpy (r, s1 + 1, 3))
     171      abort ();
     172    if (!stpncpy (r, s1 + 1, 2))
     173      abort ();
     174    r = buf3;
     175    l = "abc";
     176    l2 = 4;
     177    for (i = 0; i < 4; ++i)
     178      {
     179        if (i == l1 - 1)
     180  	r = &a.buf1[1], l = "e", l2 = 2;
     181        else if (i == l1)
     182  	r = &a.buf2[7], l = "gh", l2 = 3;
     183        else if (i == l1 + 1)
     184  	r = &buf3[5], l = "jkl", l2 = 4;
     185        else if (i == l1 + 2)
     186  	r = &a.buf1[9], l = "", l2 = 1;
     187      }
     188    if (!stpncpy (r, "", 1))
     189      abort ();
     190    /* Here, strlen (l) + 1 is known to be at most 4 and
     191       __builtin_object_size (&buf3[16], 0) is 4, so this doesn't need
     192       runtime checking.  */
     193    if (!stpncpy (&buf3[16], l, l2))
     194      abort ();
     195    if (!stpncpy (&buf3[15], "abc", l2))
     196      abort ();
     197    if (!stpncpy (&buf3[10], "fghij", l2))
     198      abort ();
     199    if (chk_calls)
     200      abort ();
     201    chk_calls = 0;
     202  }
     203  
     204  /* Test whether runtime and/or compile time checking catches
     205     buffer overflows.  */
     206  void
     207  __attribute__((noinline))
     208  test4 (void)
     209  {
     210    struct A { char buf1[10]; char buf2[10]; } a;
     211    char buf3[20];
     212  
     213    chk_fail_allowed = 1;
     214    /* Runtime checks.  */
     215    if (__builtin_setjmp (chk_fail_buf) == 0)
     216      {
     217        if (stpncpy (&a.buf2[9], s2 + 4, l1 + 1))
     218          // returned value used to prevent stpncpy calls
     219          // to be rewritten in strncpy calls
     220          i++;
     221        abort ();
     222      }
     223    if (__builtin_setjmp (chk_fail_buf) == 0)
     224      {
     225        if (stpncpy (&a.buf2[7], s3, l1 + 4))
     226          i++;
     227        abort ();
     228      }
     229    /* This should be detectable at compile time already.  */
     230    if (__builtin_setjmp (chk_fail_buf) == 0)
     231      {
     232        if (stpncpy (&buf3[19], "abc", 2))
     233          i++;
     234        abort ();
     235      }
     236    if (__builtin_setjmp (chk_fail_buf) == 0)
     237      {
     238        if (stpncpy (&buf3[18], "", 3))
     239          i++;
     240        abort ();
     241      }
     242    chk_fail_allowed = 0;
     243  }
     244  
     245  void
     246  main_test (void)
     247  {
     248  #ifndef __OPTIMIZE__
     249    /* Object size checking is only intended for -O[s123].  */
     250    return;
     251  #endif
     252    __asm ("" : "=r" (s2) : "0" (s2));
     253    __asm ("" : "=r" (s3) : "0" (s3));
     254    __asm ("" : "=r" (l1) : "0" (l1));
     255    test1 ();
     256    
     257    s4 = p;
     258    test2 ();
     259    test3 ();
     260    test4 ();
     261  }