1/* Copyright (C) 2004, 2005 Free Software Foundation. 2 3 Ensure builtin __mempcpy_chk performs correctly. */ 4 5extern void abort (void); 6typedef __SIZE_TYPE__ size_t; 7extern size_t strlen(const char *); 8extern void *memcpy (void *, const void *, size_t); 9extern void *mempcpy (void *, const void *, size_t); 10extern int memcmp (const void *, const void *, size_t); 11 12#include "chk.h" 13 14const char s1[] = "123"; 15char p[32] = ""; 16char *s2 = "defg"; 17char *s3 = "FGH"; 18size_t l1 = 1; 19 20void 21__attribute__((noinline)) 22test1 (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 mempcpy_disallowed = 1; 31#endif 32 33 /* All the mempcpy calls in this routine except last have fixed length, so 34 object size checking should be done at compile time if optimizing. */ 35 chk_calls = 0; 36 37 if (mempcpy (p, "ABCDE", 6) != p + 6 || memcmp (p, "ABCDE", 6)) 38 abort (); 39 if (mempcpy (p + 16, "VWX" + 1, 2) != p + 16 + 2 40 || memcmp (p + 16, "WX\0\0", 5)) 41 abort (); 42 if (mempcpy (p + 1, "", 1) != p + 1 + 1 || memcmp (p, "A\0CDE", 6)) 43 abort (); 44 if (mempcpy (p + 3, "FGHI", 4) != p + 3 + 4 || memcmp (p, "A\0CFGHI", 8)) 45 abort (); 46 47 i = 8; 48 memcpy (p + 20, "qrstu", 6); 49 memcpy (p + 25, "QRSTU", 6); 50 if (mempcpy (p + 25 + 1, s1, 3) != (p + 25 + 1 + 3) 51 || memcmp (p + 25, "Q123U", 6)) 52 abort (); 53 54 if (mempcpy (mempcpy (p, "abcdEFG", 4), "efg", 4) != p + 8 55 || memcmp (p, "abcdefg", 8)) 56 abort(); 57 58 /* Test at least one instance of the __builtin_ style. We do this 59 to ensure that it works and that the prototype is correct. */ 60 if (__builtin_mempcpy (p, "ABCDE", 6) != p + 6 || memcmp (p, "ABCDE", 6)) 61 abort (); 62 63 /* If the result of mempcpy is ignored, gcc should use memcpy. 64 This should be optimized always, so disallow mempcpy calls. */ 65 mempcpy_disallowed = 1; 66 mempcpy (p + 5, s3, 1); 67 if (memcmp (p, "ABCDEFg", 8)) 68 abort (); 69 70 if (chk_calls) 71 abort (); 72 chk_calls = 0; 73 74 mempcpy (p + 6, s1 + 1, l1); 75 if (memcmp (p, "ABCDEF2", 8)) 76 abort (); 77 78 /* The above mempcpy copies into an object with known size, but 79 unknown length and with result ignored, so it should be a 80 __memcpy_chk call. */ 81 if (chk_calls != 1) 82 abort (); 83 84 mempcpy_disallowed = 0; 85} 86 87long buf1[64]; 88char *buf2 = (char *) (buf1 + 32); 89long buf5[20]; 90char buf7[20]; 91 92void 93__attribute__((noinline)) 94test2_sub (long *buf3, char *buf4, char *buf6, int n) 95{ 96 int i = 0; 97 98 /* All the mempcpy/__builtin_mempcpy/__builtin___mempcpy_chk 99 calls in this routine are either fixed length, or have 100 side-effects in __builtin_object_size arguments, or 101 dst doesn't point into a known object. */ 102 chk_calls = 0; 103 104 /* These should probably be handled by store_by_pieces on most arches. */ 105 if (mempcpy (buf1, "ABCDEFGHI", 9) != (char *) buf1 + 9 106 || memcmp (buf1, "ABCDEFGHI\0", 11)) 107 abort (); 108 109 if (mempcpy (buf1, "abcdefghijklmnopq", 17) != (char *) buf1 + 17 110 || memcmp (buf1, "abcdefghijklmnopq\0", 19)) 111 abort (); 112 113 if (__builtin_mempcpy (buf3, "ABCDEF", 6) != (char *) buf1 + 6 114 || memcmp (buf1, "ABCDEFghijklmnopq\0", 19)) 115 abort (); 116 117 if (__builtin_mempcpy (buf3, "a", 1) != (char *) buf1 + 1 118 || memcmp (buf1, "aBCDEFghijklmnopq\0", 19)) 119 abort (); 120 121 if (mempcpy ((char *) buf3 + 2, "bcd" + ++i, 2) != (char *) buf1 + 4 122 || memcmp (buf1, "aBcdEFghijklmnopq\0", 19) 123 || i != 1) 124 abort (); 125 126 /* These should probably be handled by move_by_pieces on most arches. */ 127 if (mempcpy ((char *) buf3 + 4, buf5, 6) != (char *) buf1 + 10 128 || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19)) 129 abort (); 130 131 if (__builtin_mempcpy ((char *) buf1 + ++i + 8, (char *) buf5 + 1, 1) 132 != (char *) buf1 + 11 133 || memcmp (buf1, "aBcdRSTUVWSlmnopq\0", 19) 134 || i != 2) 135 abort (); 136 137 if (mempcpy ((char *) buf3 + 14, buf6, 2) != (char *) buf1 + 16 138 || memcmp (buf1, "aBcdRSTUVWSlmnrsq\0", 19)) 139 abort (); 140 141 if (mempcpy (buf3, buf5, 8) != (char *) buf1 + 8 142 || memcmp (buf1, "RSTUVWXYVWSlmnrsq\0", 19)) 143 abort (); 144 145 if (mempcpy (buf3, buf5, 17) != (char *) buf1 + 17 146 || memcmp (buf1, "RSTUVWXYZ01234567\0", 19)) 147 abort (); 148 149 __builtin_memcpy (buf3, "aBcdEFghijklmnopq\0", 19); 150 151 /* These should be handled either by movmemendM or mempcpy 152 call. */ 153 154 /* buf3 points to an unknown object, so __mempcpy_chk should not be done. */ 155 if (mempcpy ((char *) buf3 + 4, buf5, n + 6) != (char *) buf1 + 10 156 || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19)) 157 abort (); 158 159 /* This call has side-effects in dst, therefore no checking. */ 160 if (__builtin___mempcpy_chk ((char *) buf1 + ++i + 8, (char *) buf5 + 1, 161 n + 1, os ((char *) buf1 + ++i + 8)) 162 != (char *) buf1 + 12 163 || memcmp (buf1, "aBcdRSTUVWkSmnopq\0", 19) 164 || i != 3) 165 abort (); 166 167 if (mempcpy ((char *) buf3 + 14, buf6, n + 2) != (char *) buf1 + 16 168 || memcmp (buf1, "aBcdRSTUVWkSmnrsq\0", 19)) 169 abort (); 170 171 i = 1; 172 173 /* These might be handled by store_by_pieces. */ 174 if (mempcpy (buf2, "ABCDEFGHI", 9) != buf2 + 9 175 || memcmp (buf2, "ABCDEFGHI\0", 11)) 176 abort (); 177 178 if (mempcpy (buf2, "abcdefghijklmnopq", 17) != buf2 + 17 179 || memcmp (buf2, "abcdefghijklmnopq\0", 19)) 180 abort (); 181 182 if (__builtin_mempcpy (buf4, "ABCDEF", 6) != buf2 + 6 183 || memcmp (buf2, "ABCDEFghijklmnopq\0", 19)) 184 abort (); 185 186 if (__builtin_mempcpy (buf4, "a", 1) != buf2 + 1 187 || memcmp (buf2, "aBCDEFghijklmnopq\0", 19)) 188 abort (); 189 190 if (mempcpy (buf4 + 2, "bcd" + i++, 2) != buf2 + 4 191 || memcmp (buf2, "aBcdEFghijklmnopq\0", 19) 192 || i != 2) 193 abort (); 194 195 /* These might be handled by move_by_pieces. */ 196 if (mempcpy (buf4 + 4, buf7, 6) != buf2 + 10 197 || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19)) 198 abort (); 199 200 /* Side effect. */ 201 if (__builtin___mempcpy_chk (buf2 + i++ + 8, buf7 + 1, 1, 202 os (buf2 + i++ + 8)) 203 != buf2 + 11 204 || memcmp (buf2, "aBcdRSTUVWSlmnopq\0", 19) 205 || i != 3) 206 abort (); 207 208 if (mempcpy (buf4 + 14, buf6, 2) != buf2 + 16 209 || memcmp (buf2, "aBcdRSTUVWSlmnrsq\0", 19)) 210 abort (); 211 212 __builtin_memcpy (buf4, "aBcdEFghijklmnopq\0", 19); 213 214 /* These should be handled either by movmemendM or mempcpy 215 call. */ 216 if (mempcpy (buf4 + 4, buf7, n + 6) != buf2 + 10 217 || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19)) 218 abort (); 219 220 /* Side effect. */ 221 if (__builtin___mempcpy_chk (buf2 + i++ + 8, buf7 + 1, 222 n + 1, os (buf2 + i++ + 8)) 223 != buf2 + 12 224 || memcmp (buf2, "aBcdRSTUVWkSmnopq\0", 19) 225 || i != 4) 226 abort (); 227 228 if (mempcpy (buf4 + 14, buf6, n + 2) != buf2 + 16 229 || memcmp (buf2, "aBcdRSTUVWkSmnrsq\0", 19)) 230 abort (); 231 232 if (chk_calls) 233 abort (); 234} 235 236void 237__attribute__((noinline)) 238test2 (void) 239{ 240 long *x; 241 char *y; 242 int z; 243 __builtin_memcpy (buf5, "RSTUVWXYZ0123456789", 20); 244 __builtin_memcpy (buf7, "RSTUVWXYZ0123456789", 20); 245 __asm ("" : "=r" (x) : "0" (buf1)); 246 __asm ("" : "=r" (y) : "0" (buf2)); 247 __asm ("" : "=r" (z) : "0" (0)); 248 test2_sub (x, y, "rstuvwxyz", z); 249} 250 251volatile void *vx; 252 253/* Test whether compile time checking is done where it should 254 and so is runtime object size checking. */ 255void 256__attribute__((noinline)) 257test3 (void) 258{ 259 struct A { char buf1[10]; char buf2[10]; } a; 260 char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4]; 261 char buf3[20]; 262 int i; 263 size_t l; 264 265 /* The following calls should do runtime checking 266 - length is not known, but destination is. */ 267 chk_calls = 0; 268 vx = mempcpy (a.buf1 + 2, s3, l1); 269 vx = mempcpy (r, s3, l1 + 1); 270 r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; 271 vx = mempcpy (r, s2, l1 + 2); 272 vx = mempcpy (r + 2, s3, l1); 273 r = buf3; 274 for (i = 0; i < 4; ++i) 275 { 276 if (i == l1 - 1) 277 r = &a.buf1[1]; 278 else if (i == l1) 279 r = &a.buf2[7]; 280 else if (i == l1 + 1) 281 r = &buf3[5]; 282 else if (i == l1 + 2) 283 r = &a.buf1[9]; 284 } 285 vx = mempcpy (r, s2, l1); 286 if (chk_calls != 5) 287 abort (); 288 289 /* Following have known destination and known length, 290 so if optimizing certainly shouldn't result in the checking 291 variants. */ 292 chk_calls = 0; 293 vx = mempcpy (a.buf1 + 2, s3, 1); 294 vx = mempcpy (r, s3, 2); 295 r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; 296 vx = mempcpy (r, s2, 3); 297 r = buf3; 298 l = 4; 299 for (i = 0; i < 4; ++i) 300 { 301 if (i == l1 - 1) 302 r = &a.buf1[1], l = 2; 303 else if (i == l1) 304 r = &a.buf2[7], l = 3; 305 else if (i == l1 + 1) 306 r = &buf3[5], l = 4; 307 else if (i == l1 + 2) 308 r = &a.buf1[9], l = 1; 309 } 310 vx = mempcpy (r, s2, 1); 311 /* Here, l is known to be at most 4 and __builtin_object_size (&buf3[16], 0) 312 is 4, so this doesn't need runtime checking. */ 313 vx = mempcpy (&buf3[16], s2, l); 314 if (chk_calls) 315 abort (); 316 chk_calls = 0; 317} 318 319/* Test whether runtime and/or compile time checking catches 320 buffer overflows. */ 321void 322__attribute__((noinline)) 323test4 (void) 324{ 325 struct A { char buf1[10]; char buf2[10]; } a; 326 char buf3[20]; 327 328 chk_fail_allowed = 1; 329 /* Runtime checks. */ 330 if (__builtin_setjmp (chk_fail_buf) == 0) 331 { 332 vx = mempcpy (&a.buf2[9], s2, l1 + 1); 333 abort (); 334 } 335 if (__builtin_setjmp (chk_fail_buf) == 0) 336 { 337 vx = mempcpy (&a.buf2[7], s3, strlen (s3) + 1); 338 abort (); 339 } 340 /* This should be detectable at compile time already. */ 341 if (__builtin_setjmp (chk_fail_buf) == 0) 342 { 343 vx = mempcpy (&buf3[19], "ab", 2); 344 abort (); 345 } 346 chk_fail_allowed = 0; 347} 348 349#ifndef MAX_OFFSET 350#define MAX_OFFSET (sizeof (long long)) 351#endif 352 353#ifndef MAX_COPY 354#define MAX_COPY (10 * sizeof (long long)) 355#endif 356 357#ifndef MAX_EXTRA 358#define MAX_EXTRA (sizeof (long long)) 359#endif 360 361#define MAX_LENGTH (MAX_OFFSET + MAX_COPY + MAX_EXTRA) 362 363/* Use a sequence length that is not divisible by two, to make it more 364 likely to detect when words are mixed up. */ 365#define SEQUENCE_LENGTH 31 366 367static union { 368 char buf[MAX_LENGTH]; 369 long long align_int; 370 long double align_fp; 371} u1, u2; 372 373void 374__attribute__((noinline)) 375test5 (void) 376{ 377 int off1, off2, len, i; 378 char *p, *q, c; 379 380 for (off1 = 0; off1 < MAX_OFFSET; off1++) 381 for (off2 = 0; off2 < MAX_OFFSET; off2++) 382 for (len = 1; len < MAX_COPY; len++) 383 { 384 for (i = 0, c = 'A'; i < MAX_LENGTH; i++, c++) 385 { 386 u1.buf[i] = 'a'; 387 if (c >= 'A' + SEQUENCE_LENGTH) 388 c = 'A'; 389 u2.buf[i] = c; 390 } 391 392 p = mempcpy (u1.buf + off1, u2.buf + off2, len); 393 if (p != u1.buf + off1 + len) 394 abort (); 395 396 q = u1.buf; 397 for (i = 0; i < off1; i++, q++) 398 if (*q != 'a') 399 abort (); 400 401 for (i = 0, c = 'A' + off2; i < len; i++, q++, c++) 402 { 403 if (c >= 'A' + SEQUENCE_LENGTH) 404 c = 'A'; 405 if (*q != c) 406 abort (); 407 } 408 409 for (i = 0; i < MAX_EXTRA; i++, q++) 410 if (*q != 'a') 411 abort (); 412 } 413} 414 415#define TESTSIZE 80 416 417char srcb[TESTSIZE] __attribute__ ((aligned)); 418char dstb[TESTSIZE] __attribute__ ((aligned)); 419 420void 421__attribute__((noinline)) 422check (char *test, char *match, int n) 423{ 424 if (memcmp (test, match, n)) 425 abort (); 426} 427 428#define TN(n) \ 429{ memset (dstb, 0, n); vx = mempcpy (dstb, srcb, n); check (dstb, srcb, n); } 430#define T(n) \ 431TN (n) \ 432TN ((n) + 1) \ 433TN ((n) + 2) \ 434TN ((n) + 3) 435 436void 437__attribute__((noinline)) 438test6 (void) 439{ 440 int i; 441 442 chk_calls = 0; 443 444 for (i = 0; i < sizeof (srcb); ++i) 445 srcb[i] = 'a' + i % 26; 446 447 T (0); 448 T (4); 449 T (8); 450 T (12); 451 T (16); 452 T (20); 453 T (24); 454 T (28); 455 T (32); 456 T (36); 457 T (40); 458 T (44); 459 T (48); 460 T (52); 461 T (56); 462 T (60); 463 T (64); 464 T (68); 465 T (72); 466 T (76); 467 468 /* All mempcpy calls in this routine have constant arguments. */ 469 if (chk_calls) 470 abort (); 471} 472 473void 474main_test (void) 475{ 476#ifndef __OPTIMIZE__ 477 /* Object size checking is only intended for -O[s123]. */ 478 return; 479#endif 480 __asm ("" : "=r" (l1) : "0" (l1)); 481 test1 (); 482 test2 (); 483 test3 (); 484 test4 (); 485 test5 (); 486 test6 (); 487} 488