1  /* Copyright (C) 2004, 2005  Free Software Foundation.
       2  
       3     Ensure builtin __sprintf_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 *strcpy (char *, const char *);
      10  extern int memcmp (const void *, const void *, size_t);
      11  extern void *memset (void *, int, size_t);
      12  extern int sprintf (char *, const char *, ...);
      13  
      14  #include "chk.h"
      15  
      16  LOCAL const char s1[] = "123";
      17  char p[32] = "";
      18  char *s2 = "defg";
      19  char *s3 = "FGH";
      20  char *s4;
      21  size_t l1 = 1;
      22  static char buffer[32];
      23  char * volatile ptr = "barf"; /* prevent constant propagation to happen when whole program assumptions are made.  */
      24  
      25  void
      26  __attribute__((noinline))
      27  test1 (void)
      28  {
      29    chk_calls = 0;
      30    sprintf_disallowed = 1;
      31  
      32    memset (buffer, 'A', 32);
      33    sprintf (buffer, "foo");
      34    if (memcmp (buffer, "foo", 4) || buffer[4] != 'A')
      35      abort ();
      36  
      37    memset (buffer, 'A', 32);
      38    if (sprintf (buffer, "foo") != 3)
      39      abort ();
      40    if (memcmp (buffer, "foo", 4) || buffer[4] != 'A')
      41      abort ();
      42  
      43    memset (buffer, 'A', 32);
      44    sprintf (buffer, "%s", "bar");
      45    if (memcmp (buffer, "bar", 4) || buffer[4] != 'A')
      46      abort ();
      47  
      48    memset (buffer, 'A', 32);
      49    if (sprintf (buffer, "%s", "bar") != 3)
      50      abort ();
      51    if (memcmp (buffer, "bar", 4) || buffer[4] != 'A')
      52      abort ();
      53  
      54    if (chk_calls)
      55      abort ();
      56    sprintf_disallowed = 0;
      57  
      58    memset (buffer, 'A', 32);
      59    sprintf (buffer, "%s", ptr);
      60    if (memcmp (buffer, "barf", 5) || buffer[5] != 'A')
      61      abort ();
      62  
      63    memset (buffer, 'A', 32);
      64    sprintf (buffer, "%d - %c", (int) l1 + 27, *ptr);
      65    if (memcmp (buffer, "28 - b\0AAAAA", 12))
      66      abort ();
      67  
      68    if (chk_calls != 2)
      69      abort ();
      70    chk_calls = 0;
      71  
      72    sprintf (s4, "%d - %c", (int) l1 - 17, ptr[1]);
      73    if (memcmp (s4, "-16 - a", 8))
      74      abort ();
      75    if (chk_calls)
      76      abort ();
      77  }
      78  
      79  /* Test whether compile time checking is done where it should
      80     and so is runtime object size checking.  */
      81  void
      82  __attribute__((noinline))
      83  test2 (void)
      84  {
      85    struct A { char buf1[10]; char buf2[10]; } a;
      86    char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4];
      87    char buf3[20];
      88    int i;
      89  
      90    /* The following calls should do runtime checking
      91       - source length is not known, but destination is.  */
      92    chk_calls = 0;
      93    sprintf (a.buf1 + 2, "%s", s3 + 3);
      94    sprintf (r, "%s%c", s3 + 3, s3[3]);
      95    r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
      96    sprintf (r, "%c %s", s2[2], s2 + 4);
      97    sprintf (r + 2, s3 + 3);
      98    r = buf3;
      99    for (i = 0; i < 4; ++i)
     100      {
     101        if (i == l1 - 1)
     102  	r = &a.buf1[1];
     103        else if (i == l1)
     104  	r = &a.buf2[7];
     105        else if (i == l1 + 1)
     106  	r = &buf3[5];
     107        else if (i == l1 + 2)
     108  	r = &a.buf1[9];
     109      }
     110    sprintf (r, s2 + 4);
     111    if (chk_calls != 5)
     112      abort ();
     113  
     114    /* Following have known destination and known source length,
     115       so if optimizing certainly shouldn't result in the checking
     116       variants.  */
     117    chk_calls = 0;
     118    sprintf_disallowed = 1;
     119    sprintf (a.buf1 + 2, "");
     120    sprintf (r, "a");
     121    r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
     122    sprintf (r, "%s", s1 + 1);
     123    r = buf3;
     124    for (i = 0; i < 4; ++i)
     125      {
     126        if (i == l1 - 1)
     127  	r = &a.buf1[1];
     128        else if (i == l1)
     129  	r = &a.buf2[7];
     130        else if (i == l1 + 1)
     131  	r = &buf3[5];
     132        else if (i == l1 + 2)
     133  	r = &a.buf1[9];
     134      }
     135    sprintf (r, "%s", "");
     136    sprintf_disallowed = 0;
     137    /* Unknown destination and source, no checking.  */
     138    sprintf (s4, "%s %d", s3, 0);
     139    if (chk_calls)
     140      abort ();
     141  }
     142  
     143  /* Test whether runtime and/or compile time checking catches
     144     buffer overflows.  */
     145  void
     146  __attribute__((noinline))
     147  test3 (void)
     148  {
     149    struct A { char buf1[10]; char buf2[10]; } a;
     150    char buf3[20];
     151  
     152    chk_fail_allowed = 1;
     153    /* Runtime checks.  */
     154    if (__builtin_setjmp (chk_fail_buf) == 0)
     155      {
     156        sprintf (&a.buf2[9], "%c%s", s2[3], s2 + 4);
     157        abort ();
     158      }
     159    if (__builtin_setjmp (chk_fail_buf) == 0)
     160      {
     161        sprintf (&a.buf2[7], "%s%c", s3 + strlen (s3) - 2, *s3);
     162        abort ();
     163      }
     164    if (__builtin_setjmp (chk_fail_buf) == 0)
     165      {
     166        sprintf (&a.buf2[7], "%d", (int) l1 + 9999);
     167        abort ();
     168      }
     169    /* This should be detectable at compile time already.  */
     170    if (__builtin_setjmp (chk_fail_buf) == 0)
     171      {
     172        sprintf (&buf3[19], "a");
     173        abort ();
     174      }
     175    if (__builtin_setjmp (chk_fail_buf) == 0)
     176      {
     177        sprintf (&buf3[17], "%s", "abc");
     178        abort ();
     179      }
     180    chk_fail_allowed = 0;
     181  }
     182  
     183  void
     184  main_test (void)
     185  {
     186  #ifndef __OPTIMIZE__
     187    /* Object size checking is only intended for -O[s123].  */
     188    return;
     189  #endif
     190    __asm ("" : "=r" (s2) : "0" (s2));
     191    __asm ("" : "=r" (s3) : "0" (s3));
     192    __asm ("" : "=r" (l1) : "0" (l1));
     193    s4 = p;
     194    test1 ();
     195    test2 ();
     196    test3 ();
     197  }