(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.c-torture/
execute/
builtins/
vsprintf-chk.c
       1  /* Copyright (C) 2004, 2005  Free Software Foundation.
       2  
       3     Ensure builtin __vsprintf_chk performs correctly.  */
       4  
       5  #include <stdarg.h>
       6  
       7  extern void abort (void);
       8  typedef __SIZE_TYPE__ size_t;
       9  extern size_t strlen(const char *);
      10  extern void *memcpy (void *, const void *, size_t);
      11  extern char *strcpy (char *, const char *);
      12  extern int memcmp (const void *, const void *, size_t);
      13  extern void *memset (void *, int, size_t);
      14  extern int vsprintf (char *, const char *, va_list);
      15  
      16  #include "chk.h"
      17  
      18  const char s1[] = "123";
      19  char p[32] = "";
      20  char *s2 = "defg";
      21  char *s3 = "FGH";
      22  char *s4;
      23  size_t l1 = 1;
      24  static char buffer[32];
      25  char * volatile ptr = "barf";  /* prevent constant propagation to happen when whole program assumptions are made.  */
      26  
      27  int
      28  __attribute__((noinline))
      29  test1_sub (int i, ...)
      30  {
      31    int ret = 0;
      32    va_list ap;
      33    va_start (ap, i);
      34    switch (i)
      35      {
      36      case 0:
      37        vsprintf (buffer, "foo", ap);
      38        break;
      39      case 1:
      40        ret = vsprintf (buffer, "foo", ap);
      41        break;
      42      case 2:
      43        vsprintf (buffer, "%s", ap);
      44        break;
      45      case 3:
      46        ret = vsprintf (buffer, "%s", ap);
      47        break;
      48      case 4:
      49        vsprintf (buffer, "%d - %c", ap);
      50        break;
      51      case 5:
      52        vsprintf (s4, "%d - %c", ap);
      53        break;
      54      }
      55    va_end (ap);
      56    return ret;
      57  }
      58  
      59  void
      60  __attribute__((noinline))
      61  test1 (void)
      62  {
      63    chk_calls = 0;
      64    vsprintf_disallowed = 1;
      65  
      66    memset (buffer, 'A', 32);
      67    test1_sub (0);
      68    if (memcmp (buffer, "foo", 4) || buffer[4] != 'A')
      69      abort ();
      70  
      71    memset (buffer, 'A', 32);
      72    if (test1_sub (1) != 3)
      73      abort ();
      74    if (memcmp (buffer, "foo", 4) || buffer[4] != 'A')
      75      abort ();
      76  
      77    if (chk_calls)
      78      abort ();
      79    vsprintf_disallowed = 0;
      80  
      81    memset (buffer, 'A', 32);
      82    test1_sub (2, "bar");
      83    if (memcmp (buffer, "bar", 4) || buffer[4] != 'A')
      84      abort ();
      85  
      86    memset (buffer, 'A', 32);
      87    if (test1_sub (3, "bar") != 3)
      88      abort ();
      89    if (memcmp (buffer, "bar", 4) || buffer[4] != 'A')
      90      abort ();
      91  
      92    memset (buffer, 'A', 32);
      93    test1_sub (2, ptr);
      94    if (memcmp (buffer, "barf", 5) || buffer[5] != 'A')
      95      abort ();
      96  
      97    memset (buffer, 'A', 32);
      98    test1_sub (4, (int) l1 + 27, *ptr);
      99    if (memcmp (buffer, "28 - b\0AAAAA", 12))
     100      abort ();
     101  
     102    if (chk_calls != 4)
     103      abort ();
     104    chk_calls = 0;
     105  
     106    test1_sub (5, (int) l1 - 17, ptr[1]);
     107    if (memcmp (s4, "-16 - a", 8))
     108      abort ();
     109    if (chk_calls)
     110      abort ();
     111  }
     112  
     113  void
     114  __attribute__((noinline))
     115  test2_sub (int i, ...)
     116  {
     117    va_list ap;
     118    struct A { char buf1[10]; char buf2[10]; } a;
     119    char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4];
     120    char buf3[20];
     121    int j;
     122  
     123    va_start (ap, i);
     124    /* The following calls should do runtime checking
     125       - source length is not known, but destination is.  */
     126    switch (i)
     127      {
     128      case 0:
     129        vsprintf (a.buf1 + 2, "%s", ap);
     130        break;
     131      case 1:
     132        vsprintf (r, "%s%c", ap);
     133        break;
     134      case 2:
     135        r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
     136        vsprintf (r, "%c %s", ap);
     137        break;
     138      case 3:
     139        r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
     140        vsprintf (r + 2, s3 + 3, ap);
     141        break;
     142      case 4:
     143      case 7:
     144        r = buf3;
     145        for (j = 0; j < 4; ++j)
     146  	{
     147  	  if (j == l1 - 1)
     148  	    r = &a.buf1[1];
     149  	  else if (j == l1)
     150  	    r = &a.buf2[7];
     151  	  else if (j == l1 + 1)
     152  	    r = &buf3[5];
     153  	  else if (j == l1 + 2)
     154  	    r = &a.buf1[9];
     155  	}
     156        if (i == 4)
     157  	vsprintf (r, s2 + 4, ap);
     158        else
     159  	vsprintf (r, "a", ap);
     160        break;
     161      case 5:
     162        r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
     163        vsprintf (r, "%s", ap);
     164        break;
     165      case 6:
     166        vsprintf (a.buf1 + 2, "", ap);
     167        break;
     168      case 8:
     169        vsprintf (s4, "%s %d", ap);
     170        break;
     171      }
     172    va_end (ap);
     173  }
     174  
     175  /* Test whether compile time checking is done where it should
     176     and so is runtime object size checking.  */
     177  void
     178  __attribute__((noinline))
     179  test2 (void)
     180  {
     181    /* The following calls should do runtime checking
     182       - source length is not known, but destination is.  */
     183    chk_calls = 0;
     184    test2_sub (0, s3 + 3);
     185    test2_sub (1, s3 + 3, s3[3]);
     186    test2_sub (2, s2[2], s2 + 4);
     187    test2_sub (3);
     188    test2_sub (4);
     189    test2_sub (5, s1 + 1);
     190    if (chk_calls != 6)
     191      abort ();
     192  
     193    /* Following have known destination and known source length,
     194       so if optimizing certainly shouldn't result in the checking
     195       variants.  */
     196    chk_calls = 0;
     197    vsprintf_disallowed = 1;
     198    test2_sub (6);
     199    test2_sub (7);
     200    vsprintf_disallowed = 0;
     201    /* Unknown destination and source, no checking.  */
     202    test2_sub (8, s3, 0);
     203    if (chk_calls)
     204      abort ();
     205  }
     206  
     207  void
     208  __attribute__((noinline))
     209  test3_sub (int i, ...)
     210  {
     211    va_list ap;
     212    struct A { char buf1[10]; char buf2[10]; } a;
     213    char buf3[20];
     214  
     215    va_start (ap, i);
     216    /* The following calls should do runtime checking
     217       - source length is not known, but destination is.  */
     218    switch (i)
     219      {
     220      case 0:
     221        vsprintf (&a.buf2[9], "%c%s", ap);
     222        break;
     223      case 1:
     224        vsprintf (&a.buf2[7], "%s%c", ap);
     225        break;
     226      case 2:
     227        vsprintf (&a.buf2[7], "%d", ap);
     228        break;
     229      case 3:
     230        vsprintf (&buf3[17], "%s", ap);
     231        break;
     232      case 4:
     233        vsprintf (&buf3[19], "a", ap);
     234        break;
     235      }
     236    va_end (ap);
     237  }
     238  
     239  /* Test whether runtime and/or compile time checking catches
     240     buffer overflows.  */
     241  void
     242  __attribute__((noinline))
     243  test3 (void)
     244  {
     245    chk_fail_allowed = 1;
     246    /* Runtime checks.  */
     247    if (__builtin_setjmp (chk_fail_buf) == 0)
     248      {
     249        test3_sub (0, s2[3], s2 + 4);
     250        abort ();
     251      }
     252    if (__builtin_setjmp (chk_fail_buf) == 0)
     253      {
     254        test3_sub (1, s3 + strlen (s3) - 2, *s3);
     255        abort ();
     256      }
     257    if (__builtin_setjmp (chk_fail_buf) == 0)
     258      {
     259        test3_sub (2, (int) l1 + 9999);
     260        abort ();
     261      }
     262    if (__builtin_setjmp (chk_fail_buf) == 0)
     263      {
     264        test3_sub (3, "abc");
     265        abort ();
     266      }
     267    /* This should be detectable at compile time already.  */
     268    if (__builtin_setjmp (chk_fail_buf) == 0)
     269      {
     270        test3_sub (4);
     271        abort ();
     272      }
     273    chk_fail_allowed = 0;
     274  }
     275  
     276  void
     277  main_test (void)
     278  {
     279  #ifndef __OPTIMIZE__
     280    /* Object size checking is only intended for -O[s123].  */
     281    return;
     282  #endif
     283    __asm ("" : "=r" (s2) : "0" (s2));
     284    __asm ("" : "=r" (s3) : "0" (s3));
     285    __asm ("" : "=r" (l1) : "0" (l1));
     286    s4 = p;
     287    test1 ();
     288    test2 ();
     289    test3 ();
     290  }