1  /* Copyright (C) 2004, 2005  Free Software Foundation.
       2  
       3     Ensure builtin __strcpy_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  
      12  #include "chk.h"
      13  
      14  LOCAL const char s1[] = "123";
      15  char p[32] = "";
      16  char *s2 = "defg";
      17  char *s3 = "FGH";
      18  char *s4;
      19  size_t l1 = 1;
      20  
      21  void
      22  __attribute__((noinline))
      23  test1 (void)
      24  {
      25    chk_calls = 0;
      26  #ifndef __OPTIMIZE_SIZE__
      27    strcpy_disallowed = 1;
      28  #else
      29    strcpy_disallowed = 0;
      30  #endif
      31  
      32    if (strcpy (p, "abcde") != p || memcmp (p, "abcde", 6))
      33      abort ();
      34    if (strcpy (p + 16, "vwxyz" + 1) != p + 16 || memcmp (p + 16, "wxyz", 5))
      35      abort ();
      36    if (strcpy (p + 1, "") != p + 1 || memcmp (p, "a\0cde", 6))
      37      abort ();  
      38    if (strcpy (p + 3, "fghij") != p + 3 || memcmp (p, "a\0cfghij", 9))
      39      abort ();
      40  
      41    /* Test at least one instance of the __builtin_ style.  We do this
      42       to ensure that it works and that the prototype is correct.  */
      43    if (__builtin_strcpy (p, "abcde") != p || memcmp (p, "abcde", 6))
      44      abort ();
      45  
      46    strcpy_disallowed = 0;
      47    if (chk_calls)
      48      abort ();
      49  }
      50  
      51  #ifndef MAX_OFFSET
      52  #define MAX_OFFSET (sizeof (long long))
      53  #endif
      54  
      55  #ifndef MAX_COPY
      56  #define MAX_COPY (10 * sizeof (long long))
      57  #endif
      58  
      59  #ifndef MAX_EXTRA
      60  #define MAX_EXTRA (sizeof (long long))
      61  #endif
      62  
      63  #define MAX_LENGTH (MAX_OFFSET + MAX_COPY + 1 + MAX_EXTRA)
      64  
      65  /* Use a sequence length that is not divisible by two, to make it more
      66     likely to detect when words are mixed up.  */
      67  #define SEQUENCE_LENGTH 31
      68  
      69  static union {
      70    char buf[MAX_LENGTH];
      71    long long align_int;
      72    long double align_fp;
      73  } u1, u2;
      74  
      75  void
      76  __attribute__((noinline))
      77  test2 (void)
      78  {
      79    int off1, off2, len, i;
      80    char *p, *q, c;
      81  
      82    for (off1 = 0; off1 < MAX_OFFSET; off1++)
      83      for (off2 = 0; off2 < MAX_OFFSET; off2++)
      84        for (len = 1; len < MAX_COPY; len++)
      85  	{
      86  	  for (i = 0, c = 'A'; i < MAX_LENGTH; i++, c++)
      87  	    {
      88  	      u1.buf[i] = 'a';
      89  	      if (c >= 'A' + SEQUENCE_LENGTH)
      90  		c = 'A';
      91  	      u2.buf[i] = c;
      92  	    }
      93  	  u2.buf[off2 + len] = '\0';
      94  
      95  	  p = strcpy (u1.buf + off1, u2.buf + off2);
      96  	  if (p != u1.buf + off1)
      97  	    abort ();
      98  
      99  	  q = u1.buf;
     100  	  for (i = 0; i < off1; i++, q++)
     101  	    if (*q != 'a')
     102  	      abort ();
     103  
     104  	  for (i = 0, c = 'A' + off2; i < len; i++, q++, c++)
     105  	    {
     106  	      if (c >= 'A' + SEQUENCE_LENGTH)
     107  		c = 'A';
     108  	      if (*q != c)
     109  		abort ();
     110  	    }
     111  
     112  	  if (*q++ != '\0')
     113  	    abort ();
     114  	  for (i = 0; i < MAX_EXTRA; i++, q++)
     115  	    if (*q != 'a')
     116  	      abort ();
     117  	}
     118  }
     119  
     120  /* Test whether compile time checking is done where it should
     121     and so is runtime object size checking.  */
     122  void
     123  __attribute__((noinline))
     124  test3 (void)
     125  {
     126    struct A { char buf1[10]; char buf2[10]; } a;
     127    char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4];
     128    char buf3[20];
     129    int i;
     130    const char *l;
     131  
     132    /* The following calls should do runtime checking
     133       - source length is not known, but destination is.  */
     134    chk_calls = 0;
     135    strcpy (a.buf1 + 2, s3 + 3);
     136    strcpy (r, s3 + 2);
     137    r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
     138    strcpy (r, s2 + 2);
     139    strcpy (r + 2, s3 + 3);
     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    strcpy (r, s2 + 4);
     153    if (chk_calls != 5)
     154      abort ();
     155  
     156    /* Following have known destination and known source length,
     157       so if optimizing certainly shouldn't result in the checking
     158       variants.  */
     159    chk_calls = 0;
     160    strcpy (a.buf1 + 2, "");
     161    strcpy (r, "a");
     162    r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
     163    strcpy (r, s1 + 1);
     164    r = buf3;
     165    l = "abc";
     166    for (i = 0; i < 4; ++i)
     167      {
     168        if (i == l1 - 1)
     169  	r = &a.buf1[1], l = "e";
     170        else if (i == l1)
     171  	r = &a.buf2[7], l = "gh";
     172        else if (i == l1 + 1)
     173  	r = &buf3[5], l = "jkl";
     174        else if (i == l1 + 2)
     175  	r = &a.buf1[9], l = "";
     176      }
     177    strcpy (r, "");
     178    /* Here, strlen (l) + 1 is known to be at most 4 and
     179       __builtin_object_size (&buf3[16], 0) is 4, so this doesn't need
     180       runtime checking.  */
     181    strcpy (&buf3[16], l);
     182    /* Unknown destination and source, no checking.  */
     183    strcpy (s4, s3);
     184    if (chk_calls)
     185      abort ();
     186    chk_calls = 0;
     187  }
     188  
     189  /* Test whether runtime and/or compile time checking catches
     190     buffer overflows.  */
     191  void
     192  __attribute__((noinline))
     193  test4 (void)
     194  {
     195    struct A { char buf1[10]; char buf2[10]; } a;
     196    char buf3[20];
     197  
     198    chk_fail_allowed = 1;
     199    /* Runtime checks.  */
     200    if (__builtin_setjmp (chk_fail_buf) == 0)
     201      {
     202        strcpy (&a.buf2[9], s2 + 3);
     203        abort ();
     204      }
     205    if (__builtin_setjmp (chk_fail_buf) == 0)
     206      {
     207        strcpy (&a.buf2[7], s3 + strlen (s3) - 3);
     208        abort ();
     209      }
     210    /* This should be detectable at compile time already.  */
     211    if (__builtin_setjmp (chk_fail_buf) == 0)
     212      {
     213        strcpy (&buf3[19], "a");
     214        abort ();
     215      }
     216    chk_fail_allowed = 0;
     217  }
     218  
     219  void
     220  main_test (void)
     221  {
     222  #ifndef __OPTIMIZE__
     223    /* Object size checking is only intended for -O[s123].  */
     224    return;
     225  #endif
     226    __asm ("" : "=r" (s2) : "0" (s2));
     227    __asm ("" : "=r" (s3) : "0" (s3));
     228    __asm ("" : "=r" (l1) : "0" (l1));
     229    test1 ();
     230    test2 ();
     231    s4 = p;
     232    test3 ();
     233    test4 ();
     234  }