(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.c-torture/
execute/
builtins/
memmove-chk.c
       1  /* Copyright (C) 2004, 2005  Free Software Foundation.
       2  
       3     Ensure builtin __memcpy_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 void *memmove (void *, const void *, size_t);
      10  extern int memcmp (const void *, const void *, size_t);
      11  
      12  #include "chk.h"
      13  
      14  const char s1[] = "123"; 
      15  char p[32] = "";
      16  volatile char *s2 = "defg"; /* prevent constant propagation to happen when whole program assumptions are made.  */
      17  volatile char *s3 = "FGH"; /* prevent constant propagation to happen when whole program assumptions are made.  */
      18  volatile size_t l1 = 1; /* prevent constant propagation to happen when whole program assumptions are made.  */
      19  
      20  void
      21  __attribute__((noinline))
      22  test1 (void)
      23  {
      24    int i;
      25  
      26  #if defined __i386__ || defined __x86_64__
      27    /* The functions below might not be optimized into direct stores on all
      28       arches.  It depends on how many instructions would be generated and
      29       what limits the architecture chooses in STORE_BY_PIECES_P.  */
      30    memmove_disallowed = 1;
      31    memcpy_disallowed = 1;
      32  #endif
      33  
      34    /* All the memmove calls in this routine except last have fixed length, so
      35       object size checking should be done at compile time if optimizing.  */
      36    chk_calls = 0;
      37  
      38    if (memmove (p, "ABCDE", 6) != p || memcmp (p, "ABCDE", 6))
      39      abort ();
      40    if (memmove (p + 16, "VWX" + 1, 2) != p + 16
      41        || memcmp (p + 16, "WX\0\0", 5))
      42      abort ();
      43    if (memmove (p + 1, "", 1) != p + 1 || memcmp (p, "A\0CDE", 6))
      44      abort ();
      45    if (memmove (p + 3, "FGHI", 4) != p + 3 || memcmp (p, "A\0CFGHI", 8))
      46      abort ();
      47  
      48    i = 8;
      49    memmove (p + 20, "qrstu", 6);
      50    memmove (p + 25, "QRSTU", 6);
      51    if (memmove (p + 25 + 1, s1, 3) != p + 25 + 1
      52        || memcmp (p + 25, "Q123U", 6))
      53      abort ();
      54  
      55    if (memmove (memmove (p, "abcdEFG", 4) + 4, "efg", 4) != p + 4
      56        || memcmp (p, "abcdefg", 8))
      57      abort();
      58  
      59    /* Test at least one instance of the __builtin_ style.  We do this
      60       to ensure that it works and that the prototype is correct.  */
      61    if (__builtin_memmove (p, "ABCDE", 6) != p || memcmp (p, "ABCDE", 6))
      62      abort ();
      63  
      64    memmove (p + 5, s3, 1);
      65    if (memcmp (p, "ABCDEFg", 8))
      66      abort ();
      67  
      68    memmove_disallowed = 0;
      69    memcpy_disallowed = 0;
      70    if (chk_calls)
      71      abort ();
      72    chk_calls = 0;
      73  
      74    memmove (p + 6, s1 + 1, l1);
      75    if (memcmp (p, "ABCDEF2", 8))
      76      abort ();
      77  
      78    /* The above memmove copies into an object with known size, but
      79       unknown length, so it should be a __memmove_chk call.  */
      80    if (chk_calls != 1)
      81      abort ();
      82  }
      83  
      84  long buf1[64];
      85  char *buf2 = (char *) (buf1 + 32);
      86  long buf5[20];
      87  char buf7[20];
      88  
      89  void
      90  __attribute__((noinline))
      91  test2_sub (long *buf3, char *buf4, char *buf6, int n)
      92  {
      93    int i = 0;
      94  
      95    /* All the memmove/__builtin_memmove/__builtin___memmove_chk
      96       calls in this routine are either fixed length, or have
      97       side-effects in __builtin_object_size arguments, or
      98       dst doesn't point into a known object.  */
      99    chk_calls = 0;
     100  
     101    /* These should probably be handled by store_by_pieces on most arches.  */
     102    if (memmove (buf1, "ABCDEFGHI", 9) != (char *) buf1
     103        || memcmp (buf1, "ABCDEFGHI\0", 11))
     104      abort ();
     105  
     106    if (memmove (buf1, "abcdefghijklmnopq", 17) != (char *) buf1
     107        || memcmp (buf1, "abcdefghijklmnopq\0", 19))
     108      abort ();
     109  
     110    if (__builtin_memmove (buf3, "ABCDEF", 6) != (char *) buf1
     111        || memcmp (buf1, "ABCDEFghijklmnopq\0", 19))
     112      abort ();
     113  
     114    if (__builtin_memmove (buf3, "a", 1) != (char *) buf1
     115        || memcmp (buf1, "aBCDEFghijklmnopq\0", 19))
     116      abort ();
     117  
     118    if (memmove ((char *) buf3 + 2, "bcd" + ++i, 2) != (char *) buf1 + 2
     119        || memcmp (buf1, "aBcdEFghijklmnopq\0", 19)
     120        || i != 1)
     121      abort ();
     122  
     123    /* These should probably be handled by move_by_pieces on most arches.  */
     124    if (memmove ((char *) buf3 + 4, buf5, 6) != (char *) buf1 + 4
     125        || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19))
     126      abort ();
     127  
     128    if (__builtin_memmove ((char *) buf1 + ++i + 8, (char *) buf5 + 1, 1)
     129        != (char *) buf1 + 10
     130        || memcmp (buf1, "aBcdRSTUVWSlmnopq\0", 19)
     131        || i != 2)
     132      abort ();
     133  
     134    if (memmove ((char *) buf3 + 14, buf6, 2) != (char *) buf1 + 14
     135        || memcmp (buf1, "aBcdRSTUVWSlmnrsq\0", 19))
     136      abort ();
     137  
     138    if (memmove (buf3, buf5, 8) != (char *) buf1
     139        || memcmp (buf1, "RSTUVWXYVWSlmnrsq\0", 19))
     140      abort ();
     141  
     142    if (memmove (buf3, buf5, 17) != (char *) buf1
     143        || memcmp (buf1, "RSTUVWXYZ01234567\0", 19))
     144      abort ();
     145  
     146    __builtin_memmove (buf3, "aBcdEFghijklmnopq\0", 19);
     147  
     148    /* These should be handled either by movmemendM or memmove
     149       call.  */
     150  
     151    /* buf3 points to an unknown object, so __memmove_chk should not be done.  */
     152    if (memmove ((char *) buf3 + 4, buf5, n + 6) != (char *) buf1 + 4
     153        || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19))
     154      abort ();
     155  
     156    /* This call has side-effects in dst, therefore no checking.  */
     157    if (__builtin___memmove_chk ((char *) buf1 + ++i + 8, (char *) buf5 + 1,
     158  			       n + 1, os ((char *) buf1 + ++i + 8))
     159        != (char *) buf1 + 11
     160        || memcmp (buf1, "aBcdRSTUVWkSmnopq\0", 19)
     161        || i != 3)
     162      abort ();
     163  
     164    if (memmove ((char *) buf3 + 14, buf6, n + 2) != (char *) buf1 + 14
     165        || memcmp (buf1, "aBcdRSTUVWkSmnrsq\0", 19))
     166      abort ();
     167  
     168    i = 1;
     169  
     170    /* These might be handled by store_by_pieces.  */
     171    if (memmove (buf2, "ABCDEFGHI", 9) != buf2
     172        || memcmp (buf2, "ABCDEFGHI\0", 11))
     173      abort ();
     174  
     175    if (memmove (buf2, "abcdefghijklmnopq", 17) != buf2
     176        || memcmp (buf2, "abcdefghijklmnopq\0", 19))
     177      abort ();
     178  
     179    if (__builtin_memmove (buf4, "ABCDEF", 6) != buf2
     180        || memcmp (buf2, "ABCDEFghijklmnopq\0", 19))
     181      abort ();
     182  
     183    if (__builtin_memmove (buf4, "a", 1) != buf2
     184        || memcmp (buf2, "aBCDEFghijklmnopq\0", 19))
     185      abort ();
     186  
     187    if (memmove (buf4 + 2, "bcd" + i++, 2) != buf2 + 2
     188        || memcmp (buf2, "aBcdEFghijklmnopq\0", 19)
     189        || i != 2)
     190      abort ();
     191  
     192    /* These might be handled by move_by_pieces.  */
     193    if (memmove (buf4 + 4, buf7, 6) != buf2 + 4
     194        || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19))
     195      abort ();
     196  
     197    /* Side effect.  */
     198    if (__builtin___memmove_chk (buf2 + i++ + 8, buf7 + 1, 1,
     199  			       os (buf2 + i++ + 8))
     200        != buf2 + 10
     201        || memcmp (buf2, "aBcdRSTUVWSlmnopq\0", 19)
     202        || i != 3)
     203      abort ();
     204  
     205    if (memmove (buf4 + 14, buf6, 2) != buf2 + 14
     206        || memcmp (buf2, "aBcdRSTUVWSlmnrsq\0", 19))
     207      abort ();
     208  
     209    __builtin_memmove (buf4, "aBcdEFghijklmnopq\0", 19);
     210  
     211    /* These should be handled either by movmemendM or memmove
     212       call.  */
     213    if (memmove (buf4 + 4, buf7, n + 6) != buf2 + 4
     214        || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19))
     215      abort ();
     216  
     217    /* Side effect.  */
     218    if (__builtin___memmove_chk (buf2 + i++ + 8, buf7 + 1, n + 1,
     219  			       os (buf2 + i++ + 8))
     220        != buf2 + 11
     221        || memcmp (buf2, "aBcdRSTUVWkSmnopq\0", 19)
     222        || i != 4)
     223      abort ();
     224  
     225    if (memmove (buf4 + 14, buf6, n + 2) != buf2 + 14
     226        || memcmp (buf2, "aBcdRSTUVWkSmnrsq\0", 19))
     227      abort ();
     228  
     229    if (chk_calls)
     230      abort ();
     231  }
     232  
     233  void
     234  __attribute__((noinline))
     235  test2 (void)
     236  {
     237    long *x;
     238    char *y;
     239    int z;
     240    __builtin_memmove (buf5, "RSTUVWXYZ0123456789", 20);
     241    __builtin_memmove (buf7, "RSTUVWXYZ0123456789", 20);
     242   __asm ("" : "=r" (x) : "0" (buf1));
     243   __asm ("" : "=r" (y) : "0" (buf2));
     244   __asm ("" : "=r" (z) : "0" (0));
     245    test2_sub (x, y, "rstuvwxyz", z);
     246  }
     247  
     248  static const struct foo
     249  {
     250    char *s;
     251    double d;
     252    long l;
     253  } foo[] =
     254  {
     255    { "hello world1", 3.14159, 101L },
     256    { "hello world2", 3.14159, 102L },
     257    { "hello world3", 3.14159, 103L },
     258    { "hello world4", 3.14159, 104L },
     259    { "hello world5", 3.14159, 105L },
     260    { "hello world6", 3.14159, 106L }
     261  };
     262  
     263  static const struct bar
     264  {
     265    char *s;
     266    const struct foo f[3];
     267  } bar[] =
     268  {
     269    {
     270      "hello world10",
     271      {
     272        { "hello1", 3.14159, 201L },
     273        { "hello2", 3.14159, 202L },
     274        { "hello3", 3.14159, 203L },
     275      }
     276    },
     277    {
     278      "hello world11",
     279      {
     280        { "hello4", 3.14159, 204L },
     281        { "hello5", 3.14159, 205L },
     282        { "hello6", 3.14159, 206L },
     283      }
     284    }
     285  };
     286  
     287  static const int baz[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
     288  
     289  void
     290  __attribute__((noinline))
     291  test3 (void)
     292  {
     293    const char *s;
     294    struct foo f1[sizeof foo/sizeof*foo];
     295    struct bar b1[sizeof bar/sizeof*bar];
     296    int bz[sizeof baz/sizeof*baz];
     297  
     298    /* All the memmove/__builtin_memmove calls in this routine have fixed
     299       length.  */
     300    chk_calls = 0;
     301  
     302    /* All the *memmove calls below have src in read-only memory, so all
     303       of them should be optimized into memcpy.  */
     304    memmove_disallowed = 1;
     305    if (memmove (f1, foo, sizeof (foo)) != f1 || memcmp (f1, foo, sizeof (foo)))
     306      abort ();
     307    if (memmove (b1, bar, sizeof (bar)) != b1 || memcmp (b1, bar, sizeof (bar)))
     308      abort ();
     309    memmove (bz, baz, sizeof (baz));
     310    if (memcmp (bz, baz, sizeof (baz)))
     311      abort ();
     312  
     313    if (memmove (p, "abcde", 6) != p || memcmp (p, "abcde", 6))
     314      abort ();
     315    s = s1;
     316    if (memmove (p + 2, ++s, 0) != p + 2 || memcmp (p, "abcde", 6) || s != s1 + 1)
     317      abort ();
     318    if (__builtin_memmove (p + 3, "", 1) != p + 3 || memcmp (p, "abc\0e", 6))
     319      abort ();
     320    memmove (p + 2, "fghijk", 4);
     321    if (memcmp (p, "abfghi", 7))
     322      abort ();
     323    s = s1 + 1;
     324    memmove (p + 1, s++, 0);
     325    if (memcmp (p, "abfghi", 7) || s != s1 + 2)
     326      abort ();
     327    __builtin_memmove (p + 4, "ABCDE", 1);
     328    if (memcmp (p, "abfgAi", 7))
     329      abort ();
     330  
     331    /* memmove with length 1 can be optimized into memcpy if it can be
     332       expanded inline.  */
     333    if (memmove (p + 2, p + 3, 1) != p + 2)
     334      abort ();
     335    if (memcmp (p, "abggAi", 7))
     336      abort ();
     337  
     338    if (chk_calls)
     339      abort ();
     340    memmove_disallowed = 0;
     341  }
     342  
     343  /* Test whether compile time checking is done where it should
     344     and so is runtime object size checking.  */
     345  void
     346  __attribute__((noinline))
     347  test4 (void)
     348  {
     349    struct A { char buf1[10]; char buf2[10]; } a;
     350    char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4];
     351    char buf3[20];
     352    int i;
     353    size_t l;
     354  
     355    /* The following calls should do runtime checking
     356       - length is not known, but destination is.  */
     357    chk_calls = 0;
     358    memmove (a.buf1 + 2, s3, l1);
     359    memmove (r, s3, l1 + 1);
     360    r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
     361    memmove (r, s2, l1 + 2);
     362    memmove (r + 2, s3, l1);
     363    r = buf3;
     364    for (i = 0; i < 4; ++i)
     365      {
     366        if (i == l1 - 1)
     367  	r = &a.buf1[1];
     368        else if (i == l1)
     369  	r = &a.buf2[7];
     370        else if (i == l1 + 1)
     371  	r = &buf3[5];
     372        else if (i == l1 + 2)
     373  	r = &a.buf1[9];
     374      }
     375    memmove (r, s2, l1);
     376    if (chk_calls != 5)
     377      abort ();
     378  
     379    /* Following have known destination and known length,
     380       so if optimizing certainly shouldn't result in the checking
     381       variants.  */
     382    chk_calls = 0;
     383    memmove (a.buf1 + 2, s3, 1);
     384    memmove (r, s3, 2);
     385    r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7];
     386    memmove (r, s2, 3);
     387    r = buf3;
     388    l = 4;
     389    for (i = 0; i < 4; ++i)
     390      {
     391        if (i == l1 - 1)
     392  	r = &a.buf1[1], l = 2;
     393        else if (i == l1)
     394  	r = &a.buf2[7], l = 3;
     395        else if (i == l1 + 1)
     396  	r = &buf3[5], l = 4;
     397        else if (i == l1 + 2)
     398  	r = &a.buf1[9], l = 1;
     399      }
     400    memmove (r, s2, 1);
     401    /* Here, l is known to be at most 4 and __builtin_object_size (&buf3[16], 0)
     402       is 4, so this doesn't need runtime checking.  */
     403    memmove (&buf3[16], s2, l);
     404    if (chk_calls)
     405      abort ();
     406    chk_calls = 0;
     407  }
     408  
     409  /* Test whether runtime and/or compile time checking catches
     410     buffer overflows.  */
     411  void
     412  __attribute__((noinline))
     413  test5 (void)
     414  {
     415    struct A { char buf1[10]; char buf2[10]; } a;
     416    char buf3[20];
     417  
     418    chk_fail_allowed = 1;
     419    /* Runtime checks.  */
     420    if (__builtin_setjmp (chk_fail_buf) == 0)
     421      {
     422        memmove (&a.buf2[9], s2, l1 + 1);
     423        abort ();
     424      }
     425    if (__builtin_setjmp (chk_fail_buf) == 0)
     426      {
     427        memmove (&a.buf2[7], s3, strlen (s3) + 1);
     428        abort ();
     429      }
     430    /* This should be detectable at compile time already.  */
     431    if (__builtin_setjmp (chk_fail_buf) == 0)
     432      {
     433        memmove (&buf3[19], "ab", 2);
     434        abort ();
     435      }
     436    chk_fail_allowed = 0;
     437  }
     438  
     439  #ifndef MAX_OFFSET
     440  #define MAX_OFFSET (sizeof (long long))
     441  #endif
     442  
     443  #ifndef MAX_COPY
     444  #define MAX_COPY (10 * sizeof (long long))
     445  #endif
     446  
     447  #ifndef MAX_EXTRA
     448  #define MAX_EXTRA (sizeof (long long))
     449  #endif
     450  
     451  #define MAX_LENGTH (MAX_OFFSET + MAX_COPY + MAX_EXTRA)
     452  
     453  /* Use a sequence length that is not divisible by two, to make it more
     454     likely to detect when words are mixed up.  */
     455  #define SEQUENCE_LENGTH 31
     456  
     457  static union {
     458    char buf[MAX_LENGTH];
     459    long long align_int;
     460    long double align_fp;
     461  } u1, u2;
     462  
     463  void
     464  __attribute__((noinline))
     465  test6 (void)
     466  {
     467    int off1, off2, len, i;
     468    char *p, *q, c;
     469  
     470    for (off1 = 0; off1 < MAX_OFFSET; off1++)
     471      for (off2 = 0; off2 < MAX_OFFSET; off2++)
     472        for (len = 1; len < MAX_COPY; len++)
     473  	{
     474  	  for (i = 0, c = 'A'; i < MAX_LENGTH; i++, c++)
     475  	    {
     476  	      u1.buf[i] = 'a';
     477  	      if (c >= 'A' + SEQUENCE_LENGTH)
     478  		c = 'A';
     479  	      u2.buf[i] = c;
     480  	    }
     481  
     482  	  p = memmove (u1.buf + off1, u2.buf + off2, len);
     483  	  if (p != u1.buf + off1)
     484  	    abort ();
     485  
     486  	  q = u1.buf;
     487  	  for (i = 0; i < off1; i++, q++)
     488  	    if (*q != 'a')
     489  	      abort ();
     490  
     491  	  for (i = 0, c = 'A' + off2; i < len; i++, q++, c++)
     492  	    {
     493  	      if (c >= 'A' + SEQUENCE_LENGTH)
     494  		c = 'A';
     495  	      if (*q != c)
     496  		abort ();
     497  	    }
     498  
     499  	  for (i = 0; i < MAX_EXTRA; i++, q++)
     500  	    if (*q != 'a')
     501  	      abort ();
     502  	}
     503  }
     504  
     505  #define TESTSIZE 80
     506  
     507  char srcb[TESTSIZE] __attribute__ ((aligned));
     508  char dstb[TESTSIZE] __attribute__ ((aligned));
     509  
     510  void
     511  __attribute__((noinline))
     512  check (char *test, char *match, int n)
     513  {
     514    if (memcmp (test, match, n))
     515      abort ();
     516  }
     517  
     518  #define TN(n) \
     519  { memset (dstb, 0, n); memmove (dstb, srcb, n); check (dstb, srcb, n); }
     520  #define T(n) \
     521  TN (n) \
     522  TN ((n) + 1) \
     523  TN ((n) + 2) \
     524  TN ((n) + 3)
     525  
     526  void
     527  __attribute__((noinline))
     528  test7 (void)
     529  {
     530    int i;
     531  
     532    chk_calls = 0;
     533  
     534    for (i = 0; i < sizeof (srcb); ++i)
     535        srcb[i] = 'a' + i % 26;
     536  
     537    T (0);
     538    T (4);
     539    T (8);
     540    T (12);
     541    T (16);
     542    T (20);
     543    T (24);
     544    T (28);
     545    T (32);
     546    T (36);
     547    T (40);
     548    T (44);
     549    T (48);
     550    T (52);
     551    T (56);
     552    T (60);
     553    T (64);
     554    T (68);
     555    T (72);
     556    T (76);
     557  
     558    /* All memmove calls in this routine have constant arguments.  */
     559    if (chk_calls)
     560      abort ();
     561  }
     562  
     563  void
     564  main_test (void)
     565  {
     566  #ifndef __OPTIMIZE__
     567    /* Object size checking is only intended for -O[s123].  */
     568    return;
     569  #endif
     570    __asm ("" : "=r" (l1) : "0" (l1));
     571    test1 ();
     572    test2 ();
     573    __builtin_memset (p, '\0', sizeof (p));
     574    test3 ();
     575    test4 ();
     576    test5 ();
     577    test6 ();
     578    test7 ();
     579  }