diff options
Diffstat (limited to 'gcc/testsuite/gcc.c-torture/execute/builtins')
135 files changed, 8576 insertions, 0 deletions
diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/20010124-1-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/20010124-1-lib.c new file mode 100644 index 000000000..5f6a7487f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/20010124-1-lib.c @@ -0,0 +1,50 @@ +/* Verify that structure return doesn't invoke memcpy on + overlapping objects. */ + +extern void abort (void); +extern int inside_main; +typedef __SIZE_TYPE__ size_t; + +struct S { + char stuff[1024]; +}; + +union U { + struct { + int space; + struct S s; + } a; + struct { + struct S s; + int space; + } b; +}; + +struct S f(struct S *p) +{ + return *p; +} + +void g(union U *p) +{ +} + +void *memcpy(void *a, const void *b, size_t len) +{ + if (inside_main) + { + if (a < b && a+len > b) + abort (); + if (b < a && b+len > a) + abort (); + return a; + } + else + { + char *dst = (char *) a; + const char *src = (const char *) b; + while (len--) + *dst++ = *src++; + return a; + } +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/20010124-1.c b/gcc/testsuite/gcc.c-torture/execute/builtins/20010124-1.c new file mode 100644 index 000000000..816287344 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/20010124-1.c @@ -0,0 +1,30 @@ +/* Verify that structure return doesn't invoke memcpy on + overlapping objects. */ + +extern void abort (void); + +struct S { + char stuff[1024]; +}; + +union U { + struct { + int space; + struct S s; + } a; + struct { + struct S s; + int space; + } b; +}; + +struct S f(struct S *); +void g(union U *); + +void main_test(void) +{ + union U u; + u.b.s = f(&u.a.s); + u.a.s = f(&u.b.s); + g(&u); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/abs-1-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/abs-1-lib.c new file mode 100644 index 000000000..57446b263 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/abs-1-lib.c @@ -0,0 +1,22 @@ +extern void abort (void); +extern int abs_called; +extern int inside_main; + +/* The labs call should have been optimized, but the abs call + shouldn't have been. */ + +int +abs (int x) +{ + if (inside_main) + abs_called = 1; + return (x < 0 ? -x : x); +} + +long +labs (long x) +{ + if (inside_main) + abort (); + return (x < 0 ? -x : x); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/abs-1.c b/gcc/testsuite/gcc.c-torture/execute/builtins/abs-1.c new file mode 100644 index 000000000..6ca246d39 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/abs-1.c @@ -0,0 +1,22 @@ +/* Test for -fno-builtin-FUNCTION. */ +/* Origin: Joseph Myers <jsm28@cam.ac.uk>. */ +/* GCC normally handles abs and labs as built-in functions even without + optimization. So test that with -fno-builtin-abs, labs is so handled + but abs isn't. */ + +int abs_called = 0; + +extern int abs (int); +extern long labs (long); +extern void abort (void); + +void +main_test (void) +{ + if (labs (0) != 0) + abort (); + if (abs (0) != 0) + abort (); + if (!abs_called) + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/abs-1.x b/gcc/testsuite/gcc.c-torture/execute/builtins/abs-1.x new file mode 100644 index 000000000..80d76c528 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/abs-1.x @@ -0,0 +1,2 @@ +set additional_flags -fno-builtin-abs +return 0 diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/abs-2-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/abs-2-lib.c new file mode 100644 index 000000000..494e5390e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/abs-2-lib.c @@ -0,0 +1 @@ +#include "lib/abs.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/abs-2.c b/gcc/testsuite/gcc.c-torture/execute/builtins/abs-2.c new file mode 100644 index 000000000..c13c4556e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/abs-2.c @@ -0,0 +1,106 @@ +/* Test for builtin abs, labs, llabs, imaxabs. */ +/* Origin: Joseph Myers <jsm28@cam.ac.uk> */ + +#include <limits.h> +typedef __INTMAX_TYPE__ intmax_t; +#define INTMAX_MAX __INTMAX_MAX__ + +extern int abs (int); +extern long labs (long); +extern long long llabs (long long); +extern intmax_t imaxabs (intmax_t); +extern void abort (void); +extern void link_error (void); + +void +main_test (void) +{ + /* For each type, test both runtime and compile time (constant folding) + optimization. */ + volatile int i0 = 0, i1 = 1, im1 = -1, imin = -INT_MAX, imax = INT_MAX; + volatile long l0 = 0L, l1 = 1L, lm1 = -1L, lmin = -LONG_MAX, lmax = LONG_MAX; + volatile long long ll0 = 0LL, ll1 = 1LL, llm1 = -1LL; + volatile long long llmin = -__LONG_LONG_MAX__, llmax = __LONG_LONG_MAX__; + volatile intmax_t imax0 = 0, imax1 = 1, imaxm1 = -1; + volatile intmax_t imaxmin = -INTMAX_MAX, imaxmax = INTMAX_MAX; + if (abs (i0) != 0) + abort (); + if (abs (0) != 0) + link_error (); + if (abs (i1) != 1) + abort (); + if (abs (1) != 1) + link_error (); + if (abs (im1) != 1) + abort (); + if (abs (-1) != 1) + link_error (); + if (abs (imin) != INT_MAX) + abort (); + if (abs (-INT_MAX) != INT_MAX) + link_error (); + if (abs (imax) != INT_MAX) + abort (); + if (abs (INT_MAX) != INT_MAX) + link_error (); + if (labs (l0) != 0L) + abort (); + if (labs (0L) != 0L) + link_error (); + if (labs (l1) != 1L) + abort (); + if (labs (1L) != 1L) + link_error (); + if (labs (lm1) != 1L) + abort (); + if (labs (-1L) != 1L) + link_error (); + if (labs (lmin) != LONG_MAX) + abort (); + if (labs (-LONG_MAX) != LONG_MAX) + link_error (); + if (labs (lmax) != LONG_MAX) + abort (); + if (labs (LONG_MAX) != LONG_MAX) + link_error (); + if (llabs (ll0) != 0LL) + abort (); + if (llabs (0LL) != 0LL) + link_error (); + if (llabs (ll1) != 1LL) + abort (); + if (llabs (1LL) != 1LL) + link_error (); + if (llabs (llm1) != 1LL) + abort (); + if (llabs (-1LL) != 1LL) + link_error (); + if (llabs (llmin) != __LONG_LONG_MAX__) + abort (); + if (llabs (-__LONG_LONG_MAX__) != __LONG_LONG_MAX__) + link_error (); + if (llabs (llmax) != __LONG_LONG_MAX__) + abort (); + if (llabs (__LONG_LONG_MAX__) != __LONG_LONG_MAX__) + link_error (); + if (imaxabs (imax0) != 0) + abort (); + if (imaxabs (0) != 0) + link_error (); + if (imaxabs (imax1) != 1) + abort (); + if (imaxabs (1) != 1) + link_error (); + if (imaxabs (imaxm1) != 1) + abort (); + if (imaxabs (-1) != 1) + link_error (); + if (imaxabs (imaxmin) != INTMAX_MAX) + abort (); + if (imaxabs (-INTMAX_MAX) != INTMAX_MAX) + link_error (); + if (imaxabs (imaxmax) != INTMAX_MAX) + abort (); + if (imaxabs (INTMAX_MAX) != INTMAX_MAX) + link_error (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/abs-3-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/abs-3-lib.c new file mode 100644 index 000000000..494e5390e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/abs-3-lib.c @@ -0,0 +1 @@ +#include "lib/abs.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/abs-3.c b/gcc/testsuite/gcc.c-torture/execute/builtins/abs-3.c new file mode 100644 index 000000000..cb0d89eb0 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/abs-3.c @@ -0,0 +1,102 @@ +/* Test for builtin abs, labs, llabs, imaxabs. Test for __builtin versions. */ +/* Origin: Joseph Myers <jsm28@cam.ac.uk> */ + +#include <limits.h> +typedef __INTMAX_TYPE__ intmax_t; +#define INTMAX_MAX __INTMAX_MAX__ + +extern void abort (void); +extern void link_error (void); + +void +main_test (void) +{ + /* For each type, test both runtime and compile time (constant folding) + optimization. */ + volatile int i0 = 0, i1 = 1, im1 = -1, imin = -INT_MAX, imax = INT_MAX; + volatile long l0 = 0L, l1 = 1L, lm1 = -1L, lmin = -LONG_MAX, lmax = LONG_MAX; + volatile long long ll0 = 0LL, ll1 = 1LL, llm1 = -1LL; + volatile long long llmin = -__LONG_LONG_MAX__, llmax = __LONG_LONG_MAX__; + volatile intmax_t imax0 = 0, imax1 = 1, imaxm1 = -1; + volatile intmax_t imaxmin = -INTMAX_MAX, imaxmax = INTMAX_MAX; + if (__builtin_abs (i0) != 0) + abort (); + if (__builtin_abs (0) != 0) + link_error (); + if (__builtin_abs (i1) != 1) + abort (); + if (__builtin_abs (1) != 1) + link_error (); + if (__builtin_abs (im1) != 1) + abort (); + if (__builtin_abs (-1) != 1) + link_error (); + if (__builtin_abs (imin) != INT_MAX) + abort (); + if (__builtin_abs (-INT_MAX) != INT_MAX) + link_error (); + if (__builtin_abs (imax) != INT_MAX) + abort (); + if (__builtin_abs (INT_MAX) != INT_MAX) + link_error (); + if (__builtin_labs (l0) != 0L) + abort (); + if (__builtin_labs (0L) != 0L) + link_error (); + if (__builtin_labs (l1) != 1L) + abort (); + if (__builtin_labs (1L) != 1L) + link_error (); + if (__builtin_labs (lm1) != 1L) + abort (); + if (__builtin_labs (-1L) != 1L) + link_error (); + if (__builtin_labs (lmin) != LONG_MAX) + abort (); + if (__builtin_labs (-LONG_MAX) != LONG_MAX) + link_error (); + if (__builtin_labs (lmax) != LONG_MAX) + abort (); + if (__builtin_labs (LONG_MAX) != LONG_MAX) + link_error (); + if (__builtin_llabs (ll0) != 0LL) + abort (); + if (__builtin_llabs (0LL) != 0LL) + link_error (); + if (__builtin_llabs (ll1) != 1LL) + abort (); + if (__builtin_llabs (1LL) != 1LL) + link_error (); + if (__builtin_llabs (llm1) != 1LL) + abort (); + if (__builtin_llabs (-1LL) != 1LL) + link_error (); + if (__builtin_llabs (llmin) != __LONG_LONG_MAX__) + abort (); + if (__builtin_llabs (-__LONG_LONG_MAX__) != __LONG_LONG_MAX__) + link_error (); + if (__builtin_llabs (llmax) != __LONG_LONG_MAX__) + abort (); + if (__builtin_llabs (__LONG_LONG_MAX__) != __LONG_LONG_MAX__) + link_error (); + if (__builtin_imaxabs (imax0) != 0) + abort (); + if (__builtin_imaxabs (0) != 0) + link_error (); + if (__builtin_imaxabs (imax1) != 1) + abort (); + if (__builtin_imaxabs (1) != 1) + link_error (); + if (__builtin_imaxabs (imaxm1) != 1) + abort (); + if (__builtin_imaxabs (-1) != 1) + link_error (); + if (__builtin_imaxabs (imaxmin) != INTMAX_MAX) + abort (); + if (__builtin_imaxabs (-INTMAX_MAX) != INTMAX_MAX) + link_error (); + if (__builtin_imaxabs (imaxmax) != INTMAX_MAX) + abort (); + if (__builtin_imaxabs (INTMAX_MAX) != INTMAX_MAX) + link_error (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/builtins.exp b/gcc/testsuite/gcc.c-torture/execute/builtins/builtins.exp new file mode 100644 index 000000000..a54f3c1b5 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/builtins.exp @@ -0,0 +1,54 @@ +# Copyright (C) 2003, 2008 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# This harness is for testing builtin support. Each test has two files: +# +# - foo.c defines the main testing function, main_test(). +# - foo-lib.c implements the library functions that foo.c is testing. +# +# The functions in foo-lib.c will often want to abort on certain inputs. +# They can use the global variable inside_main to see whether they are +# being called from the test program or part of the common runtime. +# +# In many cases, the library functions will behave as normal at -O0 +# and abort when optimisation is enabled. Such implementations should +# go into the lib/ directory so that they can be included by any test +# that needs them. They shouldn't call any external functions in case +# those functions were overridden too. + +load_lib torture-options.exp +load_lib c-torture.exp + +torture-init +set-torture-options $C_TORTURE_OPTIONS {{}} $LTO_TORTURE_OPTIONS + +set additional_flags "" +if [istarget "powerpc-*-darwin*"] { + lappend additional_flags "-Wl,-multiply_defined,suppress" +} + +foreach src [lsort [find $srcdir/$subdir *.c]] { + if {![string match *-lib.c $src] && [runtest_file_p $runtests $src]} { + c-torture-execute [list $src \ + [file root $src]-lib.c \ + $srcdir/$subdir/lib/main.c] \ + $additional_flags + } +} + +torture-finish diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/chk.h b/gcc/testsuite/gcc.c-torture/execute/builtins/chk.h new file mode 100644 index 000000000..625fdef09 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/chk.h @@ -0,0 +1,89 @@ +#ifndef os +# define os(ptr) __builtin_object_size (ptr, 0) +#endif + +/* This is one of the alternatives for object size checking. + If dst has side-effects, size checking will never be done. */ +#undef memcpy +#define memcpy(dst, src, len) \ + __builtin___memcpy_chk (dst, src, len, os (dst)) +#undef mempcpy +#define mempcpy(dst, src, len) \ + __builtin___mempcpy_chk (dst, src, len, os (dst)) +#undef memmove +#define memmove(dst, src, len) \ + __builtin___memmove_chk (dst, src, len, os (dst)) +#undef memset +#define memset(dst, val, len) \ + __builtin___memset_chk (dst, val, len, os (dst)) +#undef strcpy +#define strcpy(dst, src) \ + __builtin___strcpy_chk (dst, src, os (dst)) +#undef stpcpy +#define stpcpy(dst, src) \ + __builtin___stpcpy_chk (dst, src, os (dst)) +#undef strcat +#define strcat(dst, src) \ + __builtin___strcat_chk (dst, src, os (dst)) +#undef strncpy +#define strncpy(dst, src, len) \ + __builtin___strncpy_chk (dst, src, len, os (dst)) +#undef strncat +#define strncat(dst, src, len) \ + __builtin___strncat_chk (dst, src, len, os (dst)) +#undef sprintf +#define sprintf(dst, ...) \ + __builtin___sprintf_chk (dst, 0, os (dst), __VA_ARGS__) +#undef vsprintf +#define vsprintf(dst, fmt, ap) \ + __builtin___vsprintf_chk (dst, 0, os (dst), fmt, ap) +#undef snprintf +#define snprintf(dst, len, ...) \ + __builtin___snprintf_chk (dst, len, 0, os (dst), __VA_ARGS__) +#undef vsnprintf +#define vsnprintf(dst, len, fmt, ap) \ + __builtin___vsnprintf_chk (dst, len, 0, os (dst), fmt, ap) + +/* Now "redefine" even builtins for the purpose of testing. */ +#undef __builtin_memcpy +#define __builtin_memcpy(dst, src, len) memcpy (dst, src, len) +#undef __builtin_mempcpy +#define __builtin_mempcpy(dst, src, len) mempcpy (dst, src, len) +#undef __builtin_memmove +#define __builtin_memmove(dst, src, len) memmove (dst, src, len) +#undef __builtin_memset +#define __builtin_memset(dst, val, len) memset (dst, val, len) +#undef __builtin_strcpy +#define __builtin_strcpy(dst, src) strcpy (dst, src) +#undef __builtin_stpcpy +#define __builtin_stpcpy(dst, src) stpcpy (dst, src) +#undef __builtin_strcat +#define __builtin_strcat(dst, src) strcat (dst, src) +#undef __builtin_strncpy +#define __builtin_strncpy(dst, src, len) strncpy (dst, src, len) +#undef __builtin_strncat +#define __builtin_strncat(dst, src, len) strncat (dst, src, len) +#undef __builtin_sprintf +#define __builtin_sprintf(dst, ...) sprintf (dst, __VA_ARGS__) +#undef __builtin_vsprintf +#define __builtin_vsprintf(dst, fmt, ap) vsprintf (dst, fmt, ap) +#undef __builtin_snprintf +#define __builtin_snprintf(dst, len, ...) snprintf (dst, len, __VA_ARGS__) +#undef __builtin_vsnprintf +#define __builtin_vsnprintf(dst, len, fmt, ap) vsnprintf (dst, len, fmt, ap) + +extern void *chk_fail_buf[]; +extern volatile int chk_fail_allowed, chk_calls; +extern volatile int memcpy_disallowed, mempcpy_disallowed, memmove_disallowed; +extern volatile int memset_disallowed, strcpy_disallowed, stpcpy_disallowed; +extern volatile int strncpy_disallowed, strcat_disallowed, strncat_disallowed; +extern volatile int sprintf_disallowed, vsprintf_disallowed; +extern volatile int snprintf_disallowed, vsnprintf_disallowed; + +/* A storage class that ensures that declarations bind locally. We want + to test non-static declarations where we know it is safe to do so. */ +#if __PIC__ && !__PIE__ +#define LOCAL static +#else +#define LOCAL +#endif diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/complex-1-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/complex-1-lib.c new file mode 100644 index 000000000..22d7db180 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/complex-1-lib.c @@ -0,0 +1,70 @@ +extern int inside_main; +extern void abort (void); +#ifdef __OPTIMIZE__ +#define ABORT_INSIDE_MAIN do { if (inside_main) abort (); } while (0) +#else +#define ABORT_INSIDE_MAIN do { } while (0) +#endif + +static float _Complex +conjf (float _Complex z) +{ + ABORT_INSIDE_MAIN; + return ~z; +} + +static double _Complex +conj (double _Complex z) +{ + ABORT_INSIDE_MAIN; + return ~z; +} + +static long double _Complex +conjl (long double _Complex z) +{ + ABORT_INSIDE_MAIN; + return ~z; +} + +static float +crealf (float _Complex z) +{ + ABORT_INSIDE_MAIN; + return __real__ z; +} + +static double +creal (double _Complex z) +{ + ABORT_INSIDE_MAIN; + return __real__ z; +} + +static long double +creall (long double _Complex z) +{ + ABORT_INSIDE_MAIN; + return __real__ z; +} + +static float +cimagf (float _Complex z) +{ + ABORT_INSIDE_MAIN; + return __imag__ z; +} + +static double +cimag (double _Complex z) +{ + ABORT_INSIDE_MAIN; + return __imag__ z; +} + +static long double +cimagl (long double _Complex z) +{ + ABORT_INSIDE_MAIN; + return __imag__ z; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/complex-1.c b/gcc/testsuite/gcc.c-torture/execute/builtins/complex-1.c new file mode 100644 index 000000000..362a0e41e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/complex-1.c @@ -0,0 +1,102 @@ +/* Test for builtin conj, creal, cimag. */ +/* Origin: Joseph Myers <jsm28@cam.ac.uk> */ + +extern float _Complex conjf (float _Complex); +extern double _Complex conj (double _Complex); +extern long double _Complex conjl (long double _Complex); + +extern float crealf (float _Complex); +extern double creal (double _Complex); +extern long double creall (long double _Complex); + +extern float cimagf (float _Complex); +extern double cimag (double _Complex); +extern long double cimagl (long double _Complex); + +extern void abort (void); +extern void link_error (void); + +void +main_test (void) +{ + /* For each type, test both runtime and compile time (constant folding) + optimization. */ + volatile float _Complex fc = 1.0F + 2.0iF; + volatile double _Complex dc = 1.0 + 2.0i; + volatile long double _Complex ldc = 1.0L + 2.0iL; + /* Test floats. */ + if (conjf (fc) != 1.0F - 2.0iF) + abort (); + if (__builtin_conjf (fc) != 1.0F - 2.0iF) + abort (); + if (conjf (1.0F + 2.0iF) != 1.0F - 2.0iF) + link_error (); + if (__builtin_conjf (1.0F + 2.0iF) != 1.0F - 2.0iF) + link_error (); + if (crealf (fc) != 1.0F) + abort (); + if (__builtin_crealf (fc) != 1.0F) + abort (); + if (crealf (1.0F + 2.0iF) != 1.0F) + link_error (); + if (__builtin_crealf (1.0F + 2.0iF) != 1.0F) + link_error (); + if (cimagf (fc) != 2.0F) + abort (); + if (__builtin_cimagf (fc) != 2.0F) + abort (); + if (cimagf (1.0F + 2.0iF) != 2.0F) + link_error (); + if (__builtin_cimagf (1.0F + 2.0iF) != 2.0F) + link_error (); + /* Test doubles. */ + if (conj (dc) != 1.0 - 2.0i) + abort (); + if (__builtin_conj (dc) != 1.0 - 2.0i) + abort (); + if (conj (1.0 + 2.0i) != 1.0 - 2.0i) + link_error (); + if (__builtin_conj (1.0 + 2.0i) != 1.0 - 2.0i) + link_error (); + if (creal (dc) != 1.0) + abort (); + if (__builtin_creal (dc) != 1.0) + abort (); + if (creal (1.0 + 2.0i) != 1.0) + link_error (); + if (__builtin_creal (1.0 + 2.0i) != 1.0) + link_error (); + if (cimag (dc) != 2.0) + abort (); + if (__builtin_cimag (dc) != 2.0) + abort (); + if (cimag (1.0 + 2.0i) != 2.0) + link_error (); + if (__builtin_cimag (1.0 + 2.0i) != 2.0) + link_error (); + /* Test long doubles. */ + if (conjl (ldc) != 1.0L - 2.0iL) + abort (); + if (__builtin_conjl (ldc) != 1.0L - 2.0iL) + abort (); + if (conjl (1.0L + 2.0iL) != 1.0L - 2.0iL) + link_error (); + if (__builtin_conjl (1.0L + 2.0iL) != 1.0L - 2.0iL) + link_error (); + if (creall (ldc) != 1.0L) + abort (); + if (__builtin_creall (ldc) != 1.0L) + abort (); + if (creall (1.0L + 2.0iL) != 1.0L) + link_error (); + if (__builtin_creall (1.0L + 2.0iL) != 1.0L) + link_error (); + if (cimagl (ldc) != 2.0L) + abort (); + if (__builtin_cimagl (ldc) != 2.0L) + abort (); + if (cimagl (1.0L + 2.0iL) != 2.0L) + link_error (); + if (__builtin_cimagl (1.0L + 2.0iL) != 2.0L) + link_error (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/fprintf-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/fprintf-lib.c new file mode 100644 index 000000000..b6a1e913d --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/fprintf-lib.c @@ -0,0 +1 @@ +#include "lib/fprintf.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/fprintf.c b/gcc/testsuite/gcc.c-torture/execute/builtins/fprintf.c new file mode 100644 index 000000000..f7db2e061 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/fprintf.c @@ -0,0 +1,61 @@ +/* Copyright (C) 2001 Free Software Foundation. + + Ensure all expected transformations of builtin fprintf occur and + that we honor side effects in the arguments. + + Written by Kaveh R. Ghazi, 1/7/2001. */ + +#include <stdio.h> +extern int fprintf_unlocked (FILE *, const char *, ...); +extern void abort(void); + +void +main_test (void) +{ + FILE *s_array[] = {stdout, NULL}, **s_ptr = s_array; + const char *const s1 = "hello world"; + const char *const s2[] = { s1, 0 }, *const*s3; + + fprintf (*s_ptr, ""); + fprintf (*s_ptr, "%s", ""); + fprintf (*s_ptr, "%s", "hello"); + fprintf (*s_ptr, "%s", "\n"); + fprintf (*s_ptr, "%s", *s2); + s3 = s2; + fprintf (*s_ptr, "%s", *s3++); + if (s3 != s2+1 || *s3 != 0) + abort(); + s3 = s2; + fprintf (*s_ptr++, "%s", *s3++); + if (s3 != s2+1 || *s3 != 0 || s_ptr != s_array+1 || *s_ptr != 0) + abort(); + + s_ptr = s_array; + fprintf (*s_ptr, "%c", '\n'); + fprintf (*s_ptr, "%c", **s2); + s3 = s2; + fprintf (*s_ptr, "%c", **s3++); + if (s3 != s2+1 || *s3 != 0) + abort(); + s3 = s2; + fprintf (*s_ptr++, "%c", **s3++); + if (s3 != s2+1 || *s3 != 0 || s_ptr != s_array+1 || *s_ptr != 0) + abort(); + + s_ptr = s_array; + fprintf (*s_ptr++, "hello world"); + if (s_ptr != s_array+1 || *s_ptr != 0) + abort(); + s_ptr = s_array; + fprintf (*s_ptr, "\n"); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + __builtin_fprintf (*s_ptr, "%s", "hello world\n"); + /* Check the unlocked style, these evaluate to nothing to avoid + problems on systems without the unlocked functions. */ + fprintf_unlocked (*s_ptr, ""); + __builtin_fprintf_unlocked (*s_ptr, ""); + fprintf_unlocked (*s_ptr, "%s", ""); + __builtin_fprintf_unlocked (*s_ptr, "%s", ""); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/fprintf.x b/gcc/testsuite/gcc.c-torture/execute/builtins/fprintf.x new file mode 100644 index 000000000..c8fdaf5b2 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/fprintf.x @@ -0,0 +1,7 @@ +load_lib target-supports.exp + +if { [check_effective_target_freestanding] } { + return 1; +} + +return 0; diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/fputs-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/fputs-lib.c new file mode 100644 index 000000000..c2292a781 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/fputs-lib.c @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <stddef.h> +extern void abort (void); +extern int inside_main; +extern size_t strlen(const char *); +int +fputs(const char *string, FILE *stream) +{ + size_t n = strlen(string); + size_t r; +#if defined __OPTIMIZE__ && !defined __OPTIMIZE_SIZE__ + if (inside_main) + abort(); +#endif + r = fwrite (string, 1, n, stream); + return n > r ? EOF : 0; +} + +/* Locking stdio doesn't matter for the purposes of this test. */ +int +fputs_unlocked(const char *string, FILE *stream) +{ + return fputs (string, stream); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/fputs.c b/gcc/testsuite/gcc.c-torture/execute/builtins/fputs.c new file mode 100644 index 000000000..93fa97364 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/fputs.c @@ -0,0 +1,65 @@ +/* Copyright (C) 2000, 2001 Free Software Foundation. + + Ensure all expected transformations of builtin fputs occur and that + we honor side effects in the stream argument. + + Written by Kaveh R. Ghazi, 10/30/2000. */ + +#include <stdio.h> +extern void abort(void); + +int i; + +void +main_test(void) +{ + FILE *s_array[] = {stdout, NULL}, **s_ptr = s_array; + const char *const s1 = "hello world"; + + fputs ("", *s_ptr); + fputs ("\n", *s_ptr); + fputs ("bye", *s_ptr); + fputs (s1, *s_ptr); + fputs (s1+5, *s_ptr); + fputs (s1+10, *s_ptr); + fputs (s1+11, *s_ptr); + + /* Check side-effects when transforming fputs -> NOP. */ + fputs ("", *s_ptr++); + if (s_ptr != s_array+1 || *s_ptr != 0) + abort(); + + /* Check side-effects when transforming fputs -> fputc. */ + s_ptr = s_array; + fputs ("\n", *s_ptr++); + if (s_ptr != s_array+1 || *s_ptr != 0) + abort(); + + /* Check side-effects when transforming fputs -> fwrite. */ + s_ptr = s_array; + fputs ("hello\n", *s_ptr++); + if (s_ptr != s_array+1 || *s_ptr != 0) + abort(); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + s_ptr = s_array; + __builtin_fputs ("", *s_ptr); + /* These builtin stubs are called by __builtin_fputs, ensure their + prototypes are set correctly too. */ + __builtin_fputc ('\n', *s_ptr); + __builtin_fwrite ("hello\n", 1, 6, *s_ptr); + /* Check the unlocked style, these evaluate to nothing to avoid + problems on systems without the unlocked functions. */ + fputs_unlocked ("", *s_ptr); + __builtin_fputs_unlocked ("", *s_ptr); + + /* Check side-effects in conditional expression. */ + s_ptr = s_array; + fputs (i++ ? "f" : "x", *s_ptr++); + if (s_ptr != s_array+1 || *s_ptr != 0 || i != 1) + abort(); + fputs (--i ? "\n" : "\n", *--s_ptr); + if (s_ptr != s_array || i != 0) + abort(); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/abs.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/abs.c new file mode 100644 index 000000000..1e0857f73 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/abs.c @@ -0,0 +1,41 @@ +extern int inside_main; +extern void abort (void); +#ifdef __OPTIMIZE__ +#define ABORT_INSIDE_MAIN do { if (inside_main) abort (); } while (0) +#else +#define ABORT_INSIDE_MAIN do { } while (0) +#endif + +typedef __INTMAX_TYPE__ intmax_t; + +__attribute__ ((__noinline__)) +int +abs (int x) +{ + ABORT_INSIDE_MAIN; + return x < 0 ? -x : x; +} + +__attribute__ ((__noinline__)) +long +labs (long x) +{ + ABORT_INSIDE_MAIN; + return x < 0 ? -x : x; +} + +__attribute__ ((__noinline__)) +long long +llabs (long long x) +{ + ABORT_INSIDE_MAIN; + return x < 0 ? -x : x; +} + +__attribute__ ((__noinline__)) +intmax_t +imaxabs (intmax_t x) +{ + ABORT_INSIDE_MAIN; + return x < 0 ? -x : x; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/bfill.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/bfill.c new file mode 100644 index 000000000..deb6cf522 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/bfill.c @@ -0,0 +1,16 @@ +extern int inside_main; + +__attribute__ ((__noinline__)) +void +bfill (void *s, __SIZE_TYPE__ n, int ch) +{ + char *p; + + for (p = s; n-- > 0; p++) + *p = ch; + +#ifdef __OPTIMIZE__ + if (inside_main) + abort (); +#endif +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/bzero.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/bzero.c new file mode 100644 index 000000000..a02b5358b --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/bzero.c @@ -0,0 +1,16 @@ +extern int inside_main; + +__attribute__ ((__noinline__)) +void +bzero (void *s, __SIZE_TYPE__ n) +{ + char *p; + + for (p = s; n-- > 0; p++) + *p = 0; + +#ifdef __OPTIMIZE__ + if (inside_main) + abort (); +#endif +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/chk.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/chk.c new file mode 100644 index 000000000..e5197902b --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/chk.c @@ -0,0 +1,478 @@ +#include <stdarg.h> +#ifdef __unix__ +#include <sys/types.h> +#endif + +extern void abort (void); + +extern int inside_main; +void *chk_fail_buf[256] __attribute__((aligned (16))); +volatile int chk_fail_allowed, chk_calls; +volatile int memcpy_disallowed, mempcpy_disallowed, memmove_disallowed; +volatile int memset_disallowed, strcpy_disallowed, stpcpy_disallowed; +volatile int strncpy_disallowed, strcat_disallowed, strncat_disallowed; +volatile int sprintf_disallowed, vsprintf_disallowed; +volatile int snprintf_disallowed, vsnprintf_disallowed; +extern __SIZE_TYPE__ strlen (const char *); +extern int vsprintf (char *, const char *, va_list); + +void __attribute__((noreturn)) +__chk_fail (void) +{ + if (chk_fail_allowed) + __builtin_longjmp (chk_fail_buf, 1); + abort (); +} + +void * +memcpy (void *dst, const void *src, __SIZE_TYPE__ n) +{ + const char *srcp; + char *dstp; + +#ifdef __OPTIMIZE__ + if (memcpy_disallowed && inside_main) + abort (); +#endif + + srcp = src; + dstp = dst; + while (n-- != 0) + *dstp++ = *srcp++; + + return dst; +} + +void * +__memcpy_chk (void *dst, const void *src, __SIZE_TYPE__ n, __SIZE_TYPE__ size) +{ + /* If size is -1, GCC should always optimize the call into memcpy. */ + if (size == (__SIZE_TYPE__) -1) + abort (); + ++chk_calls; + if (n > size) + __chk_fail (); + return memcpy (dst, src, n); +} + +void * +mempcpy (void *dst, const void *src, __SIZE_TYPE__ n) +{ + const char *srcp; + char *dstp; + +#ifdef __OPTIMIZE__ + if (mempcpy_disallowed && inside_main) + abort (); +#endif + + srcp = src; + dstp = dst; + while (n-- != 0) + *dstp++ = *srcp++; + + return dstp; +} + +void * +__mempcpy_chk (void *dst, const void *src, __SIZE_TYPE__ n, __SIZE_TYPE__ size) +{ + /* If size is -1, GCC should always optimize the call into mempcpy. */ + if (size == (__SIZE_TYPE__) -1) + abort (); + ++chk_calls; + if (n > size) + __chk_fail (); + return mempcpy (dst, src, n); +} + +void * +memmove (void *dst, const void *src, __SIZE_TYPE__ n) +{ + const char *srcp; + char *dstp; + +#ifdef __OPTIMIZE__ + if (memmove_disallowed && inside_main) + abort (); +#endif + + srcp = src; + dstp = dst; + if (srcp < dstp) + while (n-- != 0) + dstp[n] = srcp[n]; + else + while (n-- != 0) + *dstp++ = *srcp++; + + return dst; +} + +void * +__memmove_chk (void *dst, const void *src, __SIZE_TYPE__ n, __SIZE_TYPE__ size) +{ + /* If size is -1, GCC should always optimize the call into memmove. */ + if (size == (__SIZE_TYPE__) -1) + abort (); + ++chk_calls; + if (n > size) + __chk_fail (); + return memmove (dst, src, n); +} + +void * +memset (void *dst, int c, __SIZE_TYPE__ n) +{ + /* Single-byte memsets should be done inline when optimisation + is enabled. */ +#ifdef __OPTIMIZE__ + if (memset_disallowed && inside_main && n < 2) + abort (); +#endif + + while (n-- != 0) + n[(char *) dst] = c; + + return dst; +} + +void * +__memset_chk (void *dst, int c, __SIZE_TYPE__ n, __SIZE_TYPE__ size) +{ + /* If size is -1, GCC should always optimize the call into memset. */ + if (size == (__SIZE_TYPE__) -1) + abort (); + ++chk_calls; + if (n > size) + __chk_fail (); + return memset (dst, c, n); +} + +char * +strcpy (char *d, const char *s) +{ + char *r = d; +#ifdef __OPTIMIZE__ + if (strcpy_disallowed && inside_main) + abort (); +#endif + while ((*d++ = *s++)); + return r; +} + +char * +__strcpy_chk (char *d, const char *s, __SIZE_TYPE__ size) +{ + /* If size is -1, GCC should always optimize the call into strcpy. */ + if (size == (__SIZE_TYPE__) -1) + abort (); + ++chk_calls; + if (strlen (s) >= size) + __chk_fail (); + return strcpy (d, s); +} + +char * +stpcpy (char *dst, const char *src) +{ +#ifdef __OPTIMIZE__ + if (stpcpy_disallowed && inside_main) + abort (); +#endif + + while (*src != 0) + *dst++ = *src++; + + *dst = 0; + return dst; +} + +char * +__stpcpy_chk (char *d, const char *s, __SIZE_TYPE__ size) +{ + /* If size is -1, GCC should always optimize the call into stpcpy. */ + if (size == (__SIZE_TYPE__) -1) + abort (); + ++chk_calls; + if (strlen (s) >= size) + __chk_fail (); + return stpcpy (d, s); +} + +char * +strncpy (char *s1, const char *s2, __SIZE_TYPE__ n) +{ + char *dest = s1; +#ifdef __OPTIMIZE__ + if (strncpy_disallowed && inside_main) + abort(); +#endif + for (; *s2 && n; n--) + *s1++ = *s2++; + while (n--) + *s1++ = 0; + return dest; +} + +char * +__strncpy_chk (char *s1, const char *s2, __SIZE_TYPE__ n, __SIZE_TYPE__ size) +{ + /* If size is -1, GCC should always optimize the call into strncpy. */ + if (size == (__SIZE_TYPE__) -1) + abort (); + ++chk_calls; + if (n > size) + __chk_fail (); + return strncpy (s1, s2, n); +} + +char * +strcat (char *dst, const char *src) +{ + char *p = dst; + +#ifdef __OPTIMIZE__ + if (strcat_disallowed && inside_main) + abort (); +#endif + + while (*p) + p++; + while ((*p++ = *src++)) + ; + return dst; +} + +char * +__strcat_chk (char *d, const char *s, __SIZE_TYPE__ size) +{ + /* If size is -1, GCC should always optimize the call into strcat. */ + if (size == (__SIZE_TYPE__) -1) + abort (); + ++chk_calls; + if (strlen (d) + strlen (s) >= size) + __chk_fail (); + return strcat (d, s); +} + +char * +strncat (char *s1, const char *s2, __SIZE_TYPE__ n) +{ + char *dest = s1; + char c; +#ifdef __OPTIMIZE__ + if (strncat_disallowed && inside_main) + abort(); +#endif + while (*s1) s1++; + c = '\0'; + while (n > 0) + { + c = *s2++; + *s1++ = c; + if (c == '\0') + return dest; + n--; + } + if (c != '\0') + *s1 = '\0'; + return dest; +} + +char * +__strncat_chk (char *d, const char *s, __SIZE_TYPE__ n, __SIZE_TYPE__ size) +{ + __SIZE_TYPE__ len = strlen (d), n1 = n; + const char *s1 = s; + + /* If size is -1, GCC should always optimize the call into strncat. */ + if (size == (__SIZE_TYPE__) -1) + abort (); + ++chk_calls; + while (len < size && n1 > 0) + { + if (*s1++ == '\0') + break; + ++len; + --n1; + } + + if (len >= size) + __chk_fail (); + return strncat (d, s, n); +} + +/* No chk test in GCC testsuite needs more bytes than this. + As we can't expect vsnprintf to be available on the target, + assume 4096 bytes is enough. */ +static char chk_sprintf_buf[4096]; + +int +__sprintf_chk (char *str, int flag, __SIZE_TYPE__ size, const char *fmt, ...) +{ + int ret; + va_list ap; + + /* If size is -1 and flag 0, GCC should always optimize the call into + sprintf. */ + if (size == (__SIZE_TYPE__) -1 && flag == 0) + abort (); + ++chk_calls; +#ifdef __OPTIMIZE__ + if (sprintf_disallowed && inside_main) + abort(); +#endif + va_start (ap, fmt); + ret = vsprintf (chk_sprintf_buf, fmt, ap); + va_end (ap); + if (ret >= 0) + { + if (ret >= size) + __chk_fail (); + memcpy (str, chk_sprintf_buf, ret + 1); + } + return ret; +} + +int +__vsprintf_chk (char *str, int flag, __SIZE_TYPE__ size, const char *fmt, + va_list ap) +{ + int ret; + + /* If size is -1 and flag 0, GCC should always optimize the call into + vsprintf. */ + if (size == (__SIZE_TYPE__) -1 && flag == 0) + abort (); + ++chk_calls; +#ifdef __OPTIMIZE__ + if (vsprintf_disallowed && inside_main) + abort(); +#endif + ret = vsprintf (chk_sprintf_buf, fmt, ap); + if (ret >= 0) + { + if (ret >= size) + __chk_fail (); + memcpy (str, chk_sprintf_buf, ret + 1); + } + return ret; +} + +int +__snprintf_chk (char *str, __SIZE_TYPE__ len, int flag, __SIZE_TYPE__ size, + const char *fmt, ...) +{ + int ret; + va_list ap; + + /* If size is -1 and flag 0, GCC should always optimize the call into + snprintf. */ + if (size == (__SIZE_TYPE__) -1 && flag == 0) + abort (); + ++chk_calls; + if (size < len) + __chk_fail (); +#ifdef __OPTIMIZE__ + if (snprintf_disallowed && inside_main) + abort(); +#endif + va_start (ap, fmt); + ret = vsprintf (chk_sprintf_buf, fmt, ap); + va_end (ap); + if (ret >= 0) + { + if (ret < len) + memcpy (str, chk_sprintf_buf, ret + 1); + else + { + memcpy (str, chk_sprintf_buf, len - 1); + str[len - 1] = '\0'; + } + } + return ret; +} + +int +__vsnprintf_chk (char *str, __SIZE_TYPE__ len, int flag, __SIZE_TYPE__ size, + const char *fmt, va_list ap) +{ + int ret; + + /* If size is -1 and flag 0, GCC should always optimize the call into + vsnprintf. */ + if (size == (__SIZE_TYPE__) -1 && flag == 0) + abort (); + ++chk_calls; + if (size < len) + __chk_fail (); +#ifdef __OPTIMIZE__ + if (vsnprintf_disallowed && inside_main) + abort(); +#endif + ret = vsprintf (chk_sprintf_buf, fmt, ap); + if (ret >= 0) + { + if (ret < len) + memcpy (str, chk_sprintf_buf, ret + 1); + else + { + memcpy (str, chk_sprintf_buf, len - 1); + str[len - 1] = '\0'; + } + } + return ret; +} + +int +snprintf (char *str, __SIZE_TYPE__ len, const char *fmt, ...) +{ + int ret; + va_list ap; + +#ifdef __OPTIMIZE__ + if (snprintf_disallowed && inside_main) + abort(); +#endif + va_start (ap, fmt); + ret = vsprintf (chk_sprintf_buf, fmt, ap); + va_end (ap); + if (ret >= 0) + { + if (ret < len) + memcpy (str, chk_sprintf_buf, ret + 1); + else if (len) + { + memcpy (str, chk_sprintf_buf, len - 1); + str[len - 1] = '\0'; + } + } + return ret; +} + +/* uClibc's vsprintf calls vsnprintf. */ +#ifndef __UCLIBC__ +int +vsnprintf (char *str, __SIZE_TYPE__ len, const char *fmt, va_list ap) +{ + int ret; + +#ifdef __OPTIMIZE__ + if (vsnprintf_disallowed && inside_main) + abort(); +#endif + ret = vsprintf (chk_sprintf_buf, fmt, ap); + if (ret >= 0) + { + if (ret < len) + memcpy (str, chk_sprintf_buf, ret + 1); + else if (len) + { + memcpy (str, chk_sprintf_buf, len - 1); + str[len - 1] = '\0'; + } + } + return ret; +} +#endif diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/fprintf.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/fprintf.c new file mode 100644 index 000000000..853a705e8 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/fprintf.c @@ -0,0 +1,37 @@ +#include <stdio.h> +#include <stdarg.h> +extern void abort (void); +extern int inside_main; + +__attribute__ ((__noinline__)) +int +fprintf (FILE *fp, const char *string, ...) +{ + va_list ap; + int r; +#ifdef __OPTIMIZE__ + if (inside_main) + abort(); +#endif + va_start (ap, string); + r = vfprintf (fp, string, ap); + va_end (ap); + return r; +} + +/* Locking stdio doesn't matter for the purposes of this test. */ +__attribute__ ((__noinline__)) +int +fprintf_unlocked (FILE *fp, const char *string, ...) +{ + va_list ap; + int r; +#ifdef __OPTIMIZE__ + if (inside_main) + abort(); +#endif + va_start (ap, string); + r = vfprintf (fp, string, ap); + va_end (ap); + return r; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/main.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/main.c new file mode 100644 index 000000000..a9bb6c6b8 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/main.c @@ -0,0 +1,25 @@ +extern void abort(void); +extern void main_test (void); +extern void abort (void); +int inside_main; + +int +main () +{ + inside_main = 1; + main_test (); + inside_main = 0; + return 0; +} + +/* When optimizing, all the constant cases should have been + constant folded, so no calls to link_error should remain. + In any case, link_error should not be called. */ + +#ifndef __OPTIMIZE__ +void +link_error (void) +{ + abort (); +} +#endif diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/memchr.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/memchr.c new file mode 100644 index 000000000..2f15c57a7 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/memchr.c @@ -0,0 +1,22 @@ +extern void abort(void); +extern int inside_main; + +__attribute__ ((__noinline__)) +void * +memchr (const void *s, int c, __SIZE_TYPE__ n) +{ + const unsigned char uc = c; + const unsigned char *sp; + +#ifdef __OPTIMIZE__ + if (inside_main) + abort (); +#endif + + sp = s; + for (; n != 0; ++sp, --n) + if (*sp == uc) + return (void *) sp; + + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/memcmp.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/memcmp.c new file mode 100644 index 000000000..fd6556d22 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/memcmp.c @@ -0,0 +1,23 @@ +extern void abort(void); +extern int inside_main; + +__attribute__ ((__noinline__)) +int +memcmp (const void *s1, const void *s2, __SIZE_TYPE__ len) +{ + const unsigned char *sp1, *sp2; + +#ifdef __OPTIMIZE__ + if (inside_main) + abort (); +#endif + + sp1 = s1; + sp2 = s2; + while (len != 0 && *sp1 == *sp2) + sp1++, sp2++, len--; + + if (len == 0) + return 0; + return *sp1 - *sp2; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/memmove.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/memmove.c new file mode 100644 index 000000000..08fcd0801 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/memmove.c @@ -0,0 +1,32 @@ +extern void abort (void); +extern int inside_main; + +__attribute__ ((__noinline__)) +void * +memmove (void *dst, const void *src, __SIZE_TYPE__ n) +{ + char *dstp; + const char *srcp; + +#ifdef __OPTIMIZE__ + if (inside_main) + abort (); +#endif + + srcp = src; + dstp = dst; + if (srcp < dstp) + while (n-- != 0) + dstp[n] = srcp[n]; + else + while (n-- != 0) + *dstp++ = *srcp++; + + return dst; +} + +void +bcopy (const void *src, void *dst, __SIZE_TYPE__ n) +{ + memmove (dst, src, n); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/mempcpy.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/mempcpy.c new file mode 100644 index 000000000..bc16da536 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/mempcpy.c @@ -0,0 +1,22 @@ +extern void abort (void); +extern int inside_main; + +__attribute__ ((__noinline__)) +void * +mempcpy (void *dst, const void *src, __SIZE_TYPE__ n) +{ + const char *srcp; + char *dstp; + +#ifdef __OPTIMIZE__ + if (inside_main) + abort (); +#endif + + srcp = src; + dstp = dst; + while (n-- != 0) + *dstp++ = *srcp++; + + return dstp; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/memset.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/memset.c new file mode 100644 index 000000000..90545abbf --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/memset.c @@ -0,0 +1,20 @@ +extern void abort (void); +extern int inside_main; + +__attribute__ ((__noinline__)) +void * +memset (void *dst, int c, __SIZE_TYPE__ n) +{ + while (n-- != 0) + n[(char *) dst] = c; + + /* Single-byte memsets should be done inline when optimisation + is enabled. Do this after the copy in case we're being called to + initialize bss. */ +#ifdef __OPTIMIZE__ + if (inside_main && n < 2) + abort (); +#endif + + return dst; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/printf.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/printf.c new file mode 100644 index 000000000..4be7578d1 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/printf.c @@ -0,0 +1,38 @@ +#include <stdio.h> +#include <stdarg.h> +extern void abort (void); +extern int inside_main; + +__attribute__ ((__noinline__)) +int +printf (const char *string, ...) +{ + va_list ap; + int r; +#ifdef __OPTIMIZE__ + if (inside_main) + abort(); +#endif + va_start (ap, string); + r = vprintf (string, ap); + va_end (ap); + return r; +} + + +/* Locking stdio doesn't matter for the purposes of this test. */ +__attribute__ ((__noinline__)) +int +printf_unlocked (const char *string, ...) +{ + va_list ap; + int r; +#ifdef __OPTIMIZE__ + if (inside_main) + abort(); +#endif + va_start (ap, string); + r = vprintf (string, ap); + va_end (ap); + return r; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/sprintf.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/sprintf.c new file mode 100644 index 000000000..3ac447b11 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/sprintf.c @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdarg.h> +extern void abort (void); +extern int inside_main; + +__attribute__ ((__noinline__)) +int +(sprintf) (char *buf, const char *fmt, ...) +{ + va_list ap; + int r; +#ifdef __OPTIMIZE__ + if (inside_main) + abort (); +#endif + va_start (ap, fmt); + r = vsprintf (buf, fmt, ap); + va_end (ap); + return r; +} + + diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/stpcpy.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/stpcpy.c new file mode 100644 index 000000000..2c7c8178b --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/stpcpy.c @@ -0,0 +1,18 @@ +extern void abort (void); +extern int inside_main; + +__attribute__ ((__noinline__)) +char * +stpcpy (char *dst, const char *src) +{ +#ifdef __OPTIMIZE__ + if (inside_main) + abort (); +#endif + + while (*src != 0) + *dst++ = *src++; + + *dst = 0; + return dst; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strcat.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strcat.c new file mode 100644 index 000000000..d592087a9 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strcat.c @@ -0,0 +1,20 @@ +extern int inside_main; +extern void abort(void); + +__attribute__ ((__noinline__)) +char * +strcat (char *dst, const char *src) +{ + char *p = dst; + +#ifdef __OPTIMIZE__ + if (inside_main) + abort (); +#endif + + while (*p) + p++; + while ((*p++ = *src++)) + ; + return dst; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strchr.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strchr.c new file mode 100644 index 000000000..bee3d3203 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strchr.c @@ -0,0 +1,28 @@ +extern void abort (void); +extern int inside_main; + +__attribute__ ((__noinline__)) +char * +strchr (const char *s, int c) +{ +#ifdef __OPTIMIZE__ + if (inside_main) + abort (); +#endif + + for (;;) + { + if (*s == c) + return (char *) s; + if (*s == 0) + return 0; + s++; + } +} + +__attribute__ ((__noinline__)) +char * +index (const char *s, int c) +{ + return strchr (s, c); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strcmp.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strcmp.c new file mode 100644 index 000000000..82284546f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strcmp.c @@ -0,0 +1,19 @@ +extern void abort (void); +extern int inside_main; + +__attribute__ ((__noinline__)) +int +strcmp (const char *s1, const char *s2) +{ +#ifdef __OPTIMIZE__ + if (inside_main) + abort (); +#endif + + while (*s1 != 0 && *s1 == *s2) + s1++, s2++; + + if (*s1 == 0 || *s2 == 0) + return (unsigned char) *s1 - (unsigned char) *s2; + return *s1 - *s2; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strcpy.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strcpy.c new file mode 100644 index 000000000..916446623 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strcpy.c @@ -0,0 +1,15 @@ +extern void abort (void); +extern int inside_main; + +__attribute__ ((__noinline__)) +char * +strcpy (char *d, const char *s) +{ + char *r = d; +#if defined __OPTIMIZE__ && !defined __OPTIMIZE_SIZE__ + if (inside_main) + abort (); +#endif + while ((*d++ = *s++)); + return r; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strcspn.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strcspn.c new file mode 100644 index 000000000..827099637 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strcspn.c @@ -0,0 +1,22 @@ +extern void abort (void); +extern int inside_main; + +__attribute__ ((__noinline__)) +__SIZE_TYPE__ +strcspn (const char *s1, const char *s2) +{ + const char *p, *q; + +#ifdef __OPTIMIZE__ + if (inside_main) + abort(); +#endif + + for (p = s1; *p; p++) + for (q = s2; *q; q++) + if (*p == *q) + goto found; + + found: + return p - s1; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strlen.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strlen.c new file mode 100644 index 000000000..7f81c115b --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strlen.c @@ -0,0 +1,20 @@ +extern void abort (void); +extern int inside_main; + +__attribute__ ((__noinline__)) +__SIZE_TYPE__ +strlen (const char *s) +{ + __SIZE_TYPE__ i; + +#ifdef __OPTIMIZE__ + if (inside_main) + abort (); +#endif + + i = 0; + while (s[i] != 0) + i++; + + return i; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strncat.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strncat.c new file mode 100644 index 000000000..7fd334cb4 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strncat.c @@ -0,0 +1,29 @@ +extern void abort(void); +extern int inside_main; + +typedef __SIZE_TYPE__ size_t; + +__attribute__ ((__noinline__)) +char * +strncat (char *s1, const char *s2, size_t n) +{ + char *dest = s1; + char c = '\0'; +#ifdef __OPTIMIZE__ + if (inside_main) + abort(); +#endif + while (*s1) s1++; + c = '\0'; + while (n > 0) + { + c = *s2++; + *s1++ = c; + if (c == '\0') + return dest; + n--; + } + if (c != '\0') + *s1 = '\0'; + return dest; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strncmp.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strncmp.c new file mode 100644 index 000000000..7a8eb6fd2 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strncmp.c @@ -0,0 +1,27 @@ +extern void abort (void); +extern int inside_main; + +typedef __SIZE_TYPE__ size_t; + +__attribute__ ((__noinline__)) +int +strncmp(const char *s1, const char *s2, size_t n) +{ + const unsigned char *u1 = (const unsigned char *)s1; + const unsigned char *u2 = (const unsigned char *)s2; + unsigned char c1, c2; + +#ifdef __OPTIMIZE__ + if (inside_main) + abort(); +#endif + + while (n > 0) + { + c1 = *u1++, c2 = *u2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + n--; + } + return c1 - c2; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strncpy.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strncpy.c new file mode 100644 index 000000000..a6ec98b05 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strncpy.c @@ -0,0 +1,21 @@ +extern void abort(void); +extern int inside_main; + +typedef __SIZE_TYPE__ size_t; + +__attribute__ ((__noinline__)) +char * +strncpy(char *s1, const char *s2, size_t n) +{ + char *dest = s1; +#ifdef __OPTIMIZE__ + if (inside_main) + abort(); +#endif + for (; *s2 && n; n--) + *s1++ = *s2++; + while (n--) + *s1++ = 0; + return dest; +} + diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strpbrk.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strpbrk.c new file mode 100644 index 000000000..0c049272c --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strpbrk.c @@ -0,0 +1,21 @@ +extern void abort (void); +extern int inside_main; + +__attribute__ ((__noinline__)) +char * +strpbrk(const char *s1, const char *s2) +{ + const char *p; +#ifdef __OPTIMIZE__ + if (inside_main) + abort (); +#endif + while (*s1) + { + for (p = s2; *p; p++) + if (*s1 == *p) + return (char *)s1; + s1++; + } + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strrchr.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strrchr.c new file mode 100644 index 000000000..9a45af3c8 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strrchr.c @@ -0,0 +1,32 @@ +extern void abort (void); +extern int inside_main; + +__attribute__ ((__noinline__)) +char * +strrchr (const char *s, int c) +{ + __SIZE_TYPE__ i; + +#ifdef __OPTIMIZE__ + if (inside_main) + abort (); +#endif + + i = 0; + while (s[i] != 0) + i++; + + do + if (s[i] == c) + return (char *) s + i; + while (i-- != 0); + + return 0; +} + +__attribute__ ((__noinline__)) +char * +rindex (const char *s, int c) +{ + return strrchr (s, c); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strspn.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strspn.c new file mode 100644 index 000000000..622aac6ab --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strspn.c @@ -0,0 +1,25 @@ +extern void abort (void); +extern int inside_main; + +__attribute__ ((__noinline__)) +__SIZE_TYPE__ +strcspn (const char *s1, const char *s2) +{ + const char *p, *q; + +#ifdef __OPTIMIZE__ + if (inside_main) + abort(); +#endif + + for (p = s1; *p; p++) + { + for (q = s2; *q; q++) + if (*p == *q) + goto proceed; + break; + + proceed:; + } + return p - s1; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strstr.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strstr.c new file mode 100644 index 000000000..7d3544506 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strstr.c @@ -0,0 +1,29 @@ +extern void abort (void); +extern int inside_main; + +__attribute__ ((__noinline__)) +char * +strstr(const char *s1, const char *s2) +{ + const char *p, *q; + +#ifdef __OPTIMIZE__ + if (inside_main) + abort (); +#endif + + /* deliberately dumb algorithm */ + for (; *s1; s1++) + { + p = s1, q = s2; + while (*q && *p) + { + if (*q != *p) + break; + p++, q++; + } + if (*q == 0) + return (char *)s1; + } + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memchr-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memchr-lib.c new file mode 100644 index 000000000..ccea6ba7d --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memchr-lib.c @@ -0,0 +1 @@ +#include "lib/memchr.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memchr.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memchr.c new file mode 100644 index 000000000..88e731128 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memchr.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2007 Free Software Foundation. + + Ensure all expected transformations of builtin memchr occur + and perform correctly. + + Written by Paolo Carlini, 10/5/2007. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern void *memchr (const void *, int, size_t); + +void +main_test (void) +{ + const char* const foo1 = "hello world"; + + if (memchr (foo1, 'x', 11)) + abort (); + if (memchr (foo1, 'o', 11) != foo1 + 4) + abort (); + if (memchr (foo1, 'w', 2)) + abort (); + if (memchr (foo1 + 5, 'o', 6) != foo1 + 7) + abort (); + if (memchr (foo1, 'd', 11) != foo1 + 10) + abort (); + if (memchr (foo1, 'd', 10)) + abort (); + if (memchr (foo1, '\0', 11)) + abort (); + if (memchr (foo1, '\0', 12) != foo1 + 11) + abort (); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_memchr (foo1, 'r', 11) != foo1 + 8) + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memcmp-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memcmp-lib.c new file mode 100644 index 000000000..029a92e77 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memcmp-lib.c @@ -0,0 +1 @@ +#include "lib/memcmp.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memcmp.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memcmp.c new file mode 100644 index 000000000..5489048f5 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memcmp.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2001 Free Software Foundation. + + Ensure that short builtin memcmp are optimized and perform correctly. + On architectures with a cmpstrsi instruction, this test doesn't determine + which optimization is being performed, but it does check for correctness. + + Written by Roger Sayle, 12/02/2001. + Additional tests by Roger Sayle after PR 3508, 12/26/2001. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern int memcmp (const void *, const void *, size_t); +extern char *strcpy (char *, const char *); +extern void link_error (void); + +void +main_test (void) +{ + char str[8]; + + strcpy (str, "3141"); + + if ( memcmp (str, str+2, 0) != 0 ) + abort (); + if ( memcmp (str+1, str+3, 0) != 0 ) + abort (); + + if ( memcmp (str+1, str+3, 1) != 0 ) + abort (); + if ( memcmp (str, str+2, 1) >= 0 ) + abort (); + if ( memcmp (str+2, str, 1) <= 0 ) + abort (); + + if (memcmp ("abcd", "efgh", 4) >= 0) + link_error (); + if (memcmp ("abcd", "abcd", 4) != 0) + link_error (); + if (memcmp ("efgh", "abcd", 4) <= 0) + link_error (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memcpy-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memcpy-chk-lib.c new file mode 100644 index 000000000..9daf13e82 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memcpy-chk-lib.c @@ -0,0 +1 @@ +#include "lib/chk.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memcpy-chk.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memcpy-chk.c new file mode 100644 index 000000000..5b245e58e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memcpy-chk.c @@ -0,0 +1,479 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation. + + Ensure builtin __memcpy_chk performs correctly. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strlen(const char *); +extern void *memcpy (void *, const void *, size_t); +extern int memcmp (const void *, const void *, size_t); + +#include "chk.h" + +const char s1[] = "123"; +char p[32] = ""; +volatile char *s2 = "defg"; /* prevent constant propagation to happen when whole program assumptions are made. */ +volatile char *s3 = "FGH"; /* prevent constant propagation to happen when whole program assumptions are made. */ +volatile size_t l1 = 1; /* prevent constant propagation to happen when whole program assumptions are made. */ + +void +__attribute__((noinline)) +test1 (void) +{ + int i; + +#if defined __i386__ || defined __x86_64__ + /* The functions below might not be optimized into direct stores on all + arches. It depends on how many instructions would be generated and + what limits the architecture chooses in STORE_BY_PIECES_P. */ + memcpy_disallowed = 1; +#endif + + /* All the memcpy calls in this routine except last have fixed length, so + object size checking should be done at compile time if optimizing. */ + chk_calls = 0; + + if (memcpy (p, "ABCDE", 6) != p || memcmp (p, "ABCDE", 6)) + abort (); + if (memcpy (p + 16, "VWX" + 1, 2) != p + 16 + || memcmp (p + 16, "WX\0\0", 5)) + abort (); + if (memcpy (p + 1, "", 1) != p + 1 || memcmp (p, "A\0CDE", 6)) + abort (); + if (memcpy (p + 3, "FGHI", 4) != p + 3 || memcmp (p, "A\0CFGHI", 8)) + abort (); + + i = 8; + memcpy (p + 20, "qrstu", 6); + memcpy (p + 25, "QRSTU", 6); + if (memcpy (p + 25 + 1, s1, 3) != p + 25 + 1 + || memcmp (p + 25, "Q123U", 6)) + abort (); + + if (memcpy (memcpy (p, "abcdEFG", 4) + 4, "efg", 4) != p + 4 + || memcmp (p, "abcdefg", 8)) + abort(); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_memcpy (p, "ABCDE", 6) != p || memcmp (p, "ABCDE", 6)) + abort (); + + memcpy (p + 5, s3, 1); + if (memcmp (p, "ABCDEFg", 8)) + abort (); + + memcpy_disallowed = 0; + if (chk_calls) + abort (); + chk_calls = 0; + + memcpy (p + 6, s1 + 1, l1); + if (memcmp (p, "ABCDEF2", 8)) + abort (); + + /* The above memcpy copies into an object with known size, but + unknown length, so it should be a __memcpy_chk call. */ + if (chk_calls != 1) + abort (); +} + +long buf1[64]; +char *buf2 = (char *) (buf1 + 32); +long buf5[20]; +char buf7[20]; + +void +__attribute__((noinline)) +test2_sub (long *buf3, char *buf4, char *buf6, int n) +{ + int i = 0; + + /* All the memcpy/__builtin_memcpy/__builtin___memcpy_chk + calls in this routine are either fixed length, or have + side-effects in __builtin_object_size arguments, or + dst doesn't point into a known object. */ + chk_calls = 0; + + /* These should probably be handled by store_by_pieces on most arches. */ + if (memcpy (buf1, "ABCDEFGHI", 9) != (char *) buf1 + || memcmp (buf1, "ABCDEFGHI\0", 11)) + abort (); + + if (memcpy (buf1, "abcdefghijklmnopq", 17) != (char *) buf1 + || memcmp (buf1, "abcdefghijklmnopq\0", 19)) + abort (); + + if (__builtin_memcpy (buf3, "ABCDEF", 6) != (char *) buf1 + || memcmp (buf1, "ABCDEFghijklmnopq\0", 19)) + abort (); + + if (__builtin_memcpy (buf3, "a", 1) != (char *) buf1 + || memcmp (buf1, "aBCDEFghijklmnopq\0", 19)) + abort (); + + if (memcpy ((char *) buf3 + 2, "bcd" + ++i, 2) != (char *) buf1 + 2 + || memcmp (buf1, "aBcdEFghijklmnopq\0", 19) + || i != 1) + abort (); + + /* These should probably be handled by move_by_pieces on most arches. */ + if (memcpy ((char *) buf3 + 4, buf5, 6) != (char *) buf1 + 4 + || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + if (__builtin_memcpy ((char *) buf1 + ++i + 8, (char *) buf5 + 1, 1) + != (char *) buf1 + 10 + || memcmp (buf1, "aBcdRSTUVWSlmnopq\0", 19) + || i != 2) + abort (); + + if (memcpy ((char *) buf3 + 14, buf6, 2) != (char *) buf1 + 14 + || memcmp (buf1, "aBcdRSTUVWSlmnrsq\0", 19)) + abort (); + + if (memcpy (buf3, buf5, 8) != (char *) buf1 + || memcmp (buf1, "RSTUVWXYVWSlmnrsq\0", 19)) + abort (); + + if (memcpy (buf3, buf5, 17) != (char *) buf1 + || memcmp (buf1, "RSTUVWXYZ01234567\0", 19)) + abort (); + + __builtin_memcpy (buf3, "aBcdEFghijklmnopq\0", 19); + + /* These should be handled either by movmemendM or memcpy + call. */ + + /* buf3 points to an unknown object, so __memcpy_chk should not be done. */ + if (memcpy ((char *) buf3 + 4, buf5, n + 6) != (char *) buf1 + 4 + || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + /* This call has side-effects in dst, therefore no checking. */ + if (__builtin___memcpy_chk ((char *) buf1 + ++i + 8, (char *) buf5 + 1, + n + 1, os ((char *) buf1 + ++i + 8)) + != (char *) buf1 + 11 + || memcmp (buf1, "aBcdRSTUVWkSmnopq\0", 19) + || i != 3) + abort (); + + if (memcpy ((char *) buf3 + 14, buf6, n + 2) != (char *) buf1 + 14 + || memcmp (buf1, "aBcdRSTUVWkSmnrsq\0", 19)) + abort (); + + i = 1; + + /* These might be handled by store_by_pieces. */ + if (memcpy (buf2, "ABCDEFGHI", 9) != buf2 + || memcmp (buf2, "ABCDEFGHI\0", 11)) + abort (); + + if (memcpy (buf2, "abcdefghijklmnopq", 17) != buf2 + || memcmp (buf2, "abcdefghijklmnopq\0", 19)) + abort (); + + if (__builtin_memcpy (buf4, "ABCDEF", 6) != buf2 + || memcmp (buf2, "ABCDEFghijklmnopq\0", 19)) + abort (); + + if (__builtin_memcpy (buf4, "a", 1) != buf2 + || memcmp (buf2, "aBCDEFghijklmnopq\0", 19)) + abort (); + + if (memcpy (buf4 + 2, "bcd" + i++, 2) != buf2 + 2 + || memcmp (buf2, "aBcdEFghijklmnopq\0", 19) + || i != 2) + abort (); + + /* These might be handled by move_by_pieces. */ + if (memcpy (buf4 + 4, buf7, 6) != buf2 + 4 + || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + /* Side effect. */ + if (__builtin___memcpy_chk (buf2 + i++ + 8, buf7 + 1, 1, + os (buf2 + i++ + 8)) + != buf2 + 10 + || memcmp (buf2, "aBcdRSTUVWSlmnopq\0", 19) + || i != 3) + abort (); + + if (memcpy (buf4 + 14, buf6, 2) != buf2 + 14 + || memcmp (buf2, "aBcdRSTUVWSlmnrsq\0", 19)) + abort (); + + __builtin_memcpy (buf4, "aBcdEFghijklmnopq\0", 19); + + /* These should be handled either by movmemendM or memcpy + call. */ + if (memcpy (buf4 + 4, buf7, n + 6) != buf2 + 4 + || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + /* Side effect. */ + if (__builtin___memcpy_chk (buf2 + i++ + 8, buf7 + 1, n + 1, + os (buf2 + i++ + 8)) + != buf2 + 11 + || memcmp (buf2, "aBcdRSTUVWkSmnopq\0", 19) + || i != 4) + abort (); + + if (memcpy (buf4 + 14, buf6, n + 2) != buf2 + 14 + || memcmp (buf2, "aBcdRSTUVWkSmnrsq\0", 19)) + abort (); + + if (chk_calls) + abort (); +} + +void +__attribute__((noinline)) +test2 (void) +{ + long *x; + char *y; + int z; + __builtin_memcpy (buf5, "RSTUVWXYZ0123456789", 20); + __builtin_memcpy (buf7, "RSTUVWXYZ0123456789", 20); + __asm ("" : "=r" (x) : "0" (buf1)); + __asm ("" : "=r" (y) : "0" (buf2)); + __asm ("" : "=r" (z) : "0" (0)); + test2_sub (x, y, "rstuvwxyz", z); +} + +/* Test whether compile time checking is done where it should + and so is runtime object size checking. */ +void +__attribute__((noinline)) +test3 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4]; + char buf3[20]; + int i; + size_t l; + + /* The following calls should do runtime checking + - length is not known, but destination is. */ + chk_calls = 0; + memcpy (a.buf1 + 2, s3, l1); + memcpy (r, s3, l1 + 1); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + memcpy (r, s2, l1 + 2); + memcpy (r + 2, s3, l1); + r = buf3; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1]; + else if (i == l1) + r = &a.buf2[7]; + else if (i == l1 + 1) + r = &buf3[5]; + else if (i == l1 + 2) + r = &a.buf1[9]; + } + memcpy (r, s2, l1); + if (chk_calls != 5) + abort (); + + /* Following have known destination and known length, + so if optimizing certainly shouldn't result in the checking + variants. */ + chk_calls = 0; + memcpy (a.buf1 + 2, s3, 1); + memcpy (r, s3, 2); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + memcpy (r, s2, 3); + r = buf3; + l = 4; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1], l = 2; + else if (i == l1) + r = &a.buf2[7], l = 3; + else if (i == l1 + 1) + r = &buf3[5], l = 4; + else if (i == l1 + 2) + r = &a.buf1[9], l = 1; + } + memcpy (r, s2, 1); + /* Here, l is known to be at most 4 and __builtin_object_size (&buf3[16], 0) + is 4, so this doesn't need runtime checking. */ + memcpy (&buf3[16], s2, l); + if (chk_calls) + abort (); + chk_calls = 0; +} + +/* Test whether runtime and/or compile time checking catches + buffer overflows. */ +void +__attribute__((noinline)) +test4 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char buf3[20]; + + chk_fail_allowed = 1; + /* Runtime checks. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + memcpy (&a.buf2[9], s2, l1 + 1); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + memcpy (&a.buf2[7], s3, strlen (s3) + 1); + abort (); + } + /* This should be detectable at compile time already. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + memcpy (&buf3[19], "ab", 2); + abort (); + } + chk_fail_allowed = 0; +} + +#ifndef MAX_OFFSET +#define MAX_OFFSET (sizeof (long long)) +#endif + +#ifndef MAX_COPY +#define MAX_COPY (10 * sizeof (long long)) +#endif + +#ifndef MAX_EXTRA +#define MAX_EXTRA (sizeof (long long)) +#endif + +#define MAX_LENGTH (MAX_OFFSET + MAX_COPY + MAX_EXTRA) + +/* Use a sequence length that is not divisible by two, to make it more + likely to detect when words are mixed up. */ +#define SEQUENCE_LENGTH 31 + +static union { + char buf[MAX_LENGTH]; + long long align_int; + long double align_fp; +} u1, u2; + +void +__attribute__((noinline)) +test5 (void) +{ + int off1, off2, len, i; + char *p, *q, c; + + for (off1 = 0; off1 < MAX_OFFSET; off1++) + for (off2 = 0; off2 < MAX_OFFSET; off2++) + for (len = 1; len < MAX_COPY; len++) + { + for (i = 0, c = 'A'; i < MAX_LENGTH; i++, c++) + { + u1.buf[i] = 'a'; + if (c >= 'A' + SEQUENCE_LENGTH) + c = 'A'; + u2.buf[i] = c; + } + + p = memcpy (u1.buf + off1, u2.buf + off2, len); + if (p != u1.buf + off1) + abort (); + + q = u1.buf; + for (i = 0; i < off1; i++, q++) + if (*q != 'a') + abort (); + + for (i = 0, c = 'A' + off2; i < len; i++, q++, c++) + { + if (c >= 'A' + SEQUENCE_LENGTH) + c = 'A'; + if (*q != c) + abort (); + } + + for (i = 0; i < MAX_EXTRA; i++, q++) + if (*q != 'a') + abort (); + } +} + +#define TESTSIZE 80 + +char srcb[TESTSIZE] __attribute__ ((aligned)); +char dstb[TESTSIZE] __attribute__ ((aligned)); + +void +__attribute__((noinline)) +check (char *test, char *match, int n) +{ + if (memcmp (test, match, n)) + abort (); +} + +#define TN(n) \ +{ memset (dstb, 0, n); memcpy (dstb, srcb, n); check (dstb, srcb, n); } +#define T(n) \ +TN (n) \ +TN ((n) + 1) \ +TN ((n) + 2) \ +TN ((n) + 3) + +void +__attribute__((noinline)) +test6 (void) +{ + int i; + + chk_calls = 0; + + for (i = 0; i < sizeof (srcb); ++i) + srcb[i] = 'a' + i % 26; + + T (0); + T (4); + T (8); + T (12); + T (16); + T (20); + T (24); + T (28); + T (32); + T (36); + T (40); + T (44); + T (48); + T (52); + T (56); + T (60); + T (64); + T (68); + T (72); + T (76); + + /* All memcpy calls in this routine have constant arguments. */ + if (chk_calls) + abort (); +} + +void +main_test (void) +{ +#ifndef __OPTIMIZE__ + /* Object size checking is only intended for -O[s123]. */ + return; +#endif + __asm ("" : "=r" (l1) : "0" (l1)); + test1 (); + test2 (); + test3 (); + test4 (); + test5 (); + test6 (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memmove-2-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memmove-2-lib.c new file mode 100644 index 000000000..e2293ffc0 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memmove-2-lib.c @@ -0,0 +1,7 @@ +#include "lib/memmove.c" +#ifdef __vxworks +/* The RTP C library uses bzero and bfill, both of which are defined + in the same file as bcopy. */ +#include "lib/bzero.c" +#include "lib/bfill.c" +#endif diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memmove-2.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memmove-2.c new file mode 100644 index 000000000..3afe34313 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memmove-2.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2004 Free Software Foundation. + + Check builtin memmove and bcopy optimization when length is 1. + + Written by Jakub Jelinek, 9/14/2004. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern void *memmove (void *, const void *, size_t); +extern void bcopy (const void *, void *, size_t); +extern int memcmp (const void *, const void *, size_t); + +char p[32] = "abcdefg"; +char *q = p + 4; + +void +main_test (void) +{ + /* memmove with length 1 can be optimized into memcpy if it can be + expanded inline. */ + if (memmove (p + 2, p + 3, 1) != p + 2 || memcmp (p, "abddefg", 8)) + abort (); + if (memmove (p + 1, p + 1, 1) != p + 1 || memcmp (p, "abddefg", 8)) + abort (); + if (memmove (q, p + 4, 1) != p + 4 || memcmp (p, "abddefg", 8)) + abort (); + bcopy (p + 5, p + 6, 1); + if (memcmp (p, "abddeff", 8)) + abort (); + bcopy (p + 1, p + 1, 1); + if (memcmp (p, "abddeff", 8)) + abort (); + bcopy (q, p + 4, 1); + if (memcmp (p, "abddeff", 8)) + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memmove-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memmove-chk-lib.c new file mode 100644 index 000000000..9daf13e82 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memmove-chk-lib.c @@ -0,0 +1 @@ +#include "lib/chk.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memmove-chk.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memmove-chk.c new file mode 100644 index 000000000..73b35883e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memmove-chk.c @@ -0,0 +1,579 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation. + + Ensure builtin __memcpy_chk performs correctly. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strlen(const char *); +extern void *memcpy (void *, const void *, size_t); +extern void *memmove (void *, const void *, size_t); +extern int memcmp (const void *, const void *, size_t); + +#include "chk.h" + +const char s1[] = "123"; +char p[32] = ""; +volatile char *s2 = "defg"; /* prevent constant propagation to happen when whole program assumptions are made. */ +volatile char *s3 = "FGH"; /* prevent constant propagation to happen when whole program assumptions are made. */ +volatile size_t l1 = 1; /* prevent constant propagation to happen when whole program assumptions are made. */ + +void +__attribute__((noinline)) +test1 (void) +{ + int i; + +#if defined __i386__ || defined __x86_64__ + /* The functions below might not be optimized into direct stores on all + arches. It depends on how many instructions would be generated and + what limits the architecture chooses in STORE_BY_PIECES_P. */ + memmove_disallowed = 1; + memcpy_disallowed = 1; +#endif + + /* All the memmove calls in this routine except last have fixed length, so + object size checking should be done at compile time if optimizing. */ + chk_calls = 0; + + if (memmove (p, "ABCDE", 6) != p || memcmp (p, "ABCDE", 6)) + abort (); + if (memmove (p + 16, "VWX" + 1, 2) != p + 16 + || memcmp (p + 16, "WX\0\0", 5)) + abort (); + if (memmove (p + 1, "", 1) != p + 1 || memcmp (p, "A\0CDE", 6)) + abort (); + if (memmove (p + 3, "FGHI", 4) != p + 3 || memcmp (p, "A\0CFGHI", 8)) + abort (); + + i = 8; + memmove (p + 20, "qrstu", 6); + memmove (p + 25, "QRSTU", 6); + if (memmove (p + 25 + 1, s1, 3) != p + 25 + 1 + || memcmp (p + 25, "Q123U", 6)) + abort (); + + if (memmove (memmove (p, "abcdEFG", 4) + 4, "efg", 4) != p + 4 + || memcmp (p, "abcdefg", 8)) + abort(); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_memmove (p, "ABCDE", 6) != p || memcmp (p, "ABCDE", 6)) + abort (); + + memmove (p + 5, s3, 1); + if (memcmp (p, "ABCDEFg", 8)) + abort (); + + memmove_disallowed = 0; + memcpy_disallowed = 0; + if (chk_calls) + abort (); + chk_calls = 0; + + memmove (p + 6, s1 + 1, l1); + if (memcmp (p, "ABCDEF2", 8)) + abort (); + + /* The above memmove copies into an object with known size, but + unknown length, so it should be a __memmove_chk call. */ + if (chk_calls != 1) + abort (); +} + +long buf1[64]; +char *buf2 = (char *) (buf1 + 32); +long buf5[20]; +char buf7[20]; + +void +__attribute__((noinline)) +test2_sub (long *buf3, char *buf4, char *buf6, int n) +{ + int i = 0; + + /* All the memmove/__builtin_memmove/__builtin___memmove_chk + calls in this routine are either fixed length, or have + side-effects in __builtin_object_size arguments, or + dst doesn't point into a known object. */ + chk_calls = 0; + + /* These should probably be handled by store_by_pieces on most arches. */ + if (memmove (buf1, "ABCDEFGHI", 9) != (char *) buf1 + || memcmp (buf1, "ABCDEFGHI\0", 11)) + abort (); + + if (memmove (buf1, "abcdefghijklmnopq", 17) != (char *) buf1 + || memcmp (buf1, "abcdefghijklmnopq\0", 19)) + abort (); + + if (__builtin_memmove (buf3, "ABCDEF", 6) != (char *) buf1 + || memcmp (buf1, "ABCDEFghijklmnopq\0", 19)) + abort (); + + if (__builtin_memmove (buf3, "a", 1) != (char *) buf1 + || memcmp (buf1, "aBCDEFghijklmnopq\0", 19)) + abort (); + + if (memmove ((char *) buf3 + 2, "bcd" + ++i, 2) != (char *) buf1 + 2 + || memcmp (buf1, "aBcdEFghijklmnopq\0", 19) + || i != 1) + abort (); + + /* These should probably be handled by move_by_pieces on most arches. */ + if (memmove ((char *) buf3 + 4, buf5, 6) != (char *) buf1 + 4 + || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + if (__builtin_memmove ((char *) buf1 + ++i + 8, (char *) buf5 + 1, 1) + != (char *) buf1 + 10 + || memcmp (buf1, "aBcdRSTUVWSlmnopq\0", 19) + || i != 2) + abort (); + + if (memmove ((char *) buf3 + 14, buf6, 2) != (char *) buf1 + 14 + || memcmp (buf1, "aBcdRSTUVWSlmnrsq\0", 19)) + abort (); + + if (memmove (buf3, buf5, 8) != (char *) buf1 + || memcmp (buf1, "RSTUVWXYVWSlmnrsq\0", 19)) + abort (); + + if (memmove (buf3, buf5, 17) != (char *) buf1 + || memcmp (buf1, "RSTUVWXYZ01234567\0", 19)) + abort (); + + __builtin_memmove (buf3, "aBcdEFghijklmnopq\0", 19); + + /* These should be handled either by movmemendM or memmove + call. */ + + /* buf3 points to an unknown object, so __memmove_chk should not be done. */ + if (memmove ((char *) buf3 + 4, buf5, n + 6) != (char *) buf1 + 4 + || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + /* This call has side-effects in dst, therefore no checking. */ + if (__builtin___memmove_chk ((char *) buf1 + ++i + 8, (char *) buf5 + 1, + n + 1, os ((char *) buf1 + ++i + 8)) + != (char *) buf1 + 11 + || memcmp (buf1, "aBcdRSTUVWkSmnopq\0", 19) + || i != 3) + abort (); + + if (memmove ((char *) buf3 + 14, buf6, n + 2) != (char *) buf1 + 14 + || memcmp (buf1, "aBcdRSTUVWkSmnrsq\0", 19)) + abort (); + + i = 1; + + /* These might be handled by store_by_pieces. */ + if (memmove (buf2, "ABCDEFGHI", 9) != buf2 + || memcmp (buf2, "ABCDEFGHI\0", 11)) + abort (); + + if (memmove (buf2, "abcdefghijklmnopq", 17) != buf2 + || memcmp (buf2, "abcdefghijklmnopq\0", 19)) + abort (); + + if (__builtin_memmove (buf4, "ABCDEF", 6) != buf2 + || memcmp (buf2, "ABCDEFghijklmnopq\0", 19)) + abort (); + + if (__builtin_memmove (buf4, "a", 1) != buf2 + || memcmp (buf2, "aBCDEFghijklmnopq\0", 19)) + abort (); + + if (memmove (buf4 + 2, "bcd" + i++, 2) != buf2 + 2 + || memcmp (buf2, "aBcdEFghijklmnopq\0", 19) + || i != 2) + abort (); + + /* These might be handled by move_by_pieces. */ + if (memmove (buf4 + 4, buf7, 6) != buf2 + 4 + || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + /* Side effect. */ + if (__builtin___memmove_chk (buf2 + i++ + 8, buf7 + 1, 1, + os (buf2 + i++ + 8)) + != buf2 + 10 + || memcmp (buf2, "aBcdRSTUVWSlmnopq\0", 19) + || i != 3) + abort (); + + if (memmove (buf4 + 14, buf6, 2) != buf2 + 14 + || memcmp (buf2, "aBcdRSTUVWSlmnrsq\0", 19)) + abort (); + + __builtin_memmove (buf4, "aBcdEFghijklmnopq\0", 19); + + /* These should be handled either by movmemendM or memmove + call. */ + if (memmove (buf4 + 4, buf7, n + 6) != buf2 + 4 + || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + /* Side effect. */ + if (__builtin___memmove_chk (buf2 + i++ + 8, buf7 + 1, n + 1, + os (buf2 + i++ + 8)) + != buf2 + 11 + || memcmp (buf2, "aBcdRSTUVWkSmnopq\0", 19) + || i != 4) + abort (); + + if (memmove (buf4 + 14, buf6, n + 2) != buf2 + 14 + || memcmp (buf2, "aBcdRSTUVWkSmnrsq\0", 19)) + abort (); + + if (chk_calls) + abort (); +} + +void +__attribute__((noinline)) +test2 (void) +{ + long *x; + char *y; + int z; + __builtin_memmove (buf5, "RSTUVWXYZ0123456789", 20); + __builtin_memmove (buf7, "RSTUVWXYZ0123456789", 20); + __asm ("" : "=r" (x) : "0" (buf1)); + __asm ("" : "=r" (y) : "0" (buf2)); + __asm ("" : "=r" (z) : "0" (0)); + test2_sub (x, y, "rstuvwxyz", z); +} + +static const struct foo +{ + char *s; + double d; + long l; +} foo[] = +{ + { "hello world1", 3.14159, 101L }, + { "hello world2", 3.14159, 102L }, + { "hello world3", 3.14159, 103L }, + { "hello world4", 3.14159, 104L }, + { "hello world5", 3.14159, 105L }, + { "hello world6", 3.14159, 106L } +}; + +static const struct bar +{ + char *s; + const struct foo f[3]; +} bar[] = +{ + { + "hello world10", + { + { "hello1", 3.14159, 201L }, + { "hello2", 3.14159, 202L }, + { "hello3", 3.14159, 203L }, + } + }, + { + "hello world11", + { + { "hello4", 3.14159, 204L }, + { "hello5", 3.14159, 205L }, + { "hello6", 3.14159, 206L }, + } + } +}; + +static const int baz[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; + +void +__attribute__((noinline)) +test3 (void) +{ + const char *s; + struct foo f1[sizeof foo/sizeof*foo]; + struct bar b1[sizeof bar/sizeof*bar]; + int bz[sizeof baz/sizeof*baz]; + + /* All the memmove/__builtin_memmove calls in this routine have fixed + length. */ + chk_calls = 0; + + /* All the *memmove calls below have src in read-only memory, so all + of them should be optimized into memcpy. */ + memmove_disallowed = 1; + if (memmove (f1, foo, sizeof (foo)) != f1 || memcmp (f1, foo, sizeof (foo))) + abort (); + if (memmove (b1, bar, sizeof (bar)) != b1 || memcmp (b1, bar, sizeof (bar))) + abort (); + memmove (bz, baz, sizeof (baz)); + if (memcmp (bz, baz, sizeof (baz))) + abort (); + + if (memmove (p, "abcde", 6) != p || memcmp (p, "abcde", 6)) + abort (); + s = s1; + if (memmove (p + 2, ++s, 0) != p + 2 || memcmp (p, "abcde", 6) || s != s1 + 1) + abort (); + if (__builtin_memmove (p + 3, "", 1) != p + 3 || memcmp (p, "abc\0e", 6)) + abort (); + memmove (p + 2, "fghijk", 4); + if (memcmp (p, "abfghi", 7)) + abort (); + s = s1 + 1; + memmove (p + 1, s++, 0); + if (memcmp (p, "abfghi", 7) || s != s1 + 2) + abort (); + __builtin_memmove (p + 4, "ABCDE", 1); + if (memcmp (p, "abfgAi", 7)) + abort (); + + /* memmove with length 1 can be optimized into memcpy if it can be + expanded inline. */ + if (memmove (p + 2, p + 3, 1) != p + 2) + abort (); + if (memcmp (p, "abggAi", 7)) + abort (); + + if (chk_calls) + abort (); + memmove_disallowed = 0; +} + +/* Test whether compile time checking is done where it should + and so is runtime object size checking. */ +void +__attribute__((noinline)) +test4 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4]; + char buf3[20]; + int i; + size_t l; + + /* The following calls should do runtime checking + - length is not known, but destination is. */ + chk_calls = 0; + memmove (a.buf1 + 2, s3, l1); + memmove (r, s3, l1 + 1); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + memmove (r, s2, l1 + 2); + memmove (r + 2, s3, l1); + r = buf3; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1]; + else if (i == l1) + r = &a.buf2[7]; + else if (i == l1 + 1) + r = &buf3[5]; + else if (i == l1 + 2) + r = &a.buf1[9]; + } + memmove (r, s2, l1); + if (chk_calls != 5) + abort (); + + /* Following have known destination and known length, + so if optimizing certainly shouldn't result in the checking + variants. */ + chk_calls = 0; + memmove (a.buf1 + 2, s3, 1); + memmove (r, s3, 2); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + memmove (r, s2, 3); + r = buf3; + l = 4; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1], l = 2; + else if (i == l1) + r = &a.buf2[7], l = 3; + else if (i == l1 + 1) + r = &buf3[5], l = 4; + else if (i == l1 + 2) + r = &a.buf1[9], l = 1; + } + memmove (r, s2, 1); + /* Here, l is known to be at most 4 and __builtin_object_size (&buf3[16], 0) + is 4, so this doesn't need runtime checking. */ + memmove (&buf3[16], s2, l); + if (chk_calls) + abort (); + chk_calls = 0; +} + +/* Test whether runtime and/or compile time checking catches + buffer overflows. */ +void +__attribute__((noinline)) +test5 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char buf3[20]; + + chk_fail_allowed = 1; + /* Runtime checks. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + memmove (&a.buf2[9], s2, l1 + 1); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + memmove (&a.buf2[7], s3, strlen (s3) + 1); + abort (); + } + /* This should be detectable at compile time already. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + memmove (&buf3[19], "ab", 2); + abort (); + } + chk_fail_allowed = 0; +} + +#ifndef MAX_OFFSET +#define MAX_OFFSET (sizeof (long long)) +#endif + +#ifndef MAX_COPY +#define MAX_COPY (10 * sizeof (long long)) +#endif + +#ifndef MAX_EXTRA +#define MAX_EXTRA (sizeof (long long)) +#endif + +#define MAX_LENGTH (MAX_OFFSET + MAX_COPY + MAX_EXTRA) + +/* Use a sequence length that is not divisible by two, to make it more + likely to detect when words are mixed up. */ +#define SEQUENCE_LENGTH 31 + +static union { + char buf[MAX_LENGTH]; + long long align_int; + long double align_fp; +} u1, u2; + +void +__attribute__((noinline)) +test6 (void) +{ + int off1, off2, len, i; + char *p, *q, c; + + for (off1 = 0; off1 < MAX_OFFSET; off1++) + for (off2 = 0; off2 < MAX_OFFSET; off2++) + for (len = 1; len < MAX_COPY; len++) + { + for (i = 0, c = 'A'; i < MAX_LENGTH; i++, c++) + { + u1.buf[i] = 'a'; + if (c >= 'A' + SEQUENCE_LENGTH) + c = 'A'; + u2.buf[i] = c; + } + + p = memmove (u1.buf + off1, u2.buf + off2, len); + if (p != u1.buf + off1) + abort (); + + q = u1.buf; + for (i = 0; i < off1; i++, q++) + if (*q != 'a') + abort (); + + for (i = 0, c = 'A' + off2; i < len; i++, q++, c++) + { + if (c >= 'A' + SEQUENCE_LENGTH) + c = 'A'; + if (*q != c) + abort (); + } + + for (i = 0; i < MAX_EXTRA; i++, q++) + if (*q != 'a') + abort (); + } +} + +#define TESTSIZE 80 + +char srcb[TESTSIZE] __attribute__ ((aligned)); +char dstb[TESTSIZE] __attribute__ ((aligned)); + +void +__attribute__((noinline)) +check (char *test, char *match, int n) +{ + if (memcmp (test, match, n)) + abort (); +} + +#define TN(n) \ +{ memset (dstb, 0, n); memmove (dstb, srcb, n); check (dstb, srcb, n); } +#define T(n) \ +TN (n) \ +TN ((n) + 1) \ +TN ((n) + 2) \ +TN ((n) + 3) + +void +__attribute__((noinline)) +test7 (void) +{ + int i; + + chk_calls = 0; + + for (i = 0; i < sizeof (srcb); ++i) + srcb[i] = 'a' + i % 26; + + T (0); + T (4); + T (8); + T (12); + T (16); + T (20); + T (24); + T (28); + T (32); + T (36); + T (40); + T (44); + T (48); + T (52); + T (56); + T (60); + T (64); + T (68); + T (72); + T (76); + + /* All memmove calls in this routine have constant arguments. */ + if (chk_calls) + abort (); +} + +void +main_test (void) +{ +#ifndef __OPTIMIZE__ + /* Object size checking is only intended for -O[s123]. */ + return; +#endif + __asm ("" : "=r" (l1) : "0" (l1)); + test1 (); + test2 (); + __builtin_memset (p, '\0', sizeof (p)); + test3 (); + test4 (); + test5 (); + test6 (); + test7 (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memmove-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memmove-lib.c new file mode 100644 index 000000000..e2293ffc0 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memmove-lib.c @@ -0,0 +1,7 @@ +#include "lib/memmove.c" +#ifdef __vxworks +/* The RTP C library uses bzero and bfill, both of which are defined + in the same file as bcopy. */ +#include "lib/bzero.c" +#include "lib/bfill.c" +#endif diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memmove.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memmove.c new file mode 100644 index 000000000..f52332c6c --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memmove.c @@ -0,0 +1,90 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation. + + Ensure builtin memmove and bcopy perform correctly. + + Written by Jakub Jelinek, 4/26/2003. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern void *memmove (void *, const void *, size_t); +extern void bcopy (const void *, void *, size_t); +extern int memcmp (const void *, const void *, size_t); + +const char s1[] = "123"; +char p[32] = ""; + +static const struct foo +{ + char *s; + double d; + long l; +} foo[] = +{ + { "hello world1", 3.14159, 101L }, + { "hello world2", 3.14159, 102L }, + { "hello world3", 3.14159, 103L }, + { "hello world4", 3.14159, 104L }, + { "hello world5", 3.14159, 105L }, + { "hello world6", 3.14159, 106L } +}; + +static const struct bar +{ + char *s; + const struct foo f[3]; +} bar[] = +{ + { + "hello world10", + { + { "hello1", 3.14159, 201L }, + { "hello2", 3.14159, 202L }, + { "hello3", 3.14159, 203L }, + } + }, + { + "hello world11", + { + { "hello4", 3.14159, 204L }, + { "hello5", 3.14159, 205L }, + { "hello6", 3.14159, 206L }, + } + } +}; + +static const int baz[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; + +void +main_test (void) +{ + const char *s; + struct foo f1[sizeof foo/sizeof*foo]; + struct bar b1[sizeof bar/sizeof*bar]; + int bz[sizeof baz/sizeof*baz]; + + if (memmove (f1, foo, sizeof (foo)) != f1 || memcmp (f1, foo, sizeof (foo))) + abort (); + if (memmove (b1, bar, sizeof (bar)) != b1 || memcmp (b1, bar, sizeof (bar))) + abort (); + bcopy (baz, bz, sizeof (baz)); + if (memcmp (bz, baz, sizeof (baz))) + abort (); + + if (memmove (p, "abcde", 6) != p || memcmp (p, "abcde", 6)) + abort (); + s = s1; + if (memmove (p + 2, ++s, 0) != p + 2 || memcmp (p, "abcde", 6) || s != s1 + 1) + abort (); + if (__builtin_memmove (p + 3, "", 1) != p + 3 || memcmp (p, "abc\0e", 6)) + abort (); + bcopy ("fghijk", p + 2, 4); + if (memcmp (p, "abfghi", 7)) + abort (); + s = s1 + 1; + bcopy (s++, p + 1, 0); + if (memcmp (p, "abfghi", 7) || s != s1 + 2) + abort (); + __builtin_bcopy ("ABCDE", p + 4, 1); + if (memcmp (p, "abfgAi", 7)) + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memops-asm-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memops-asm-lib.c new file mode 100644 index 000000000..00005298d --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memops-asm-lib.c @@ -0,0 +1,97 @@ +extern void abort (void); +extern int inside_main; +typedef __SIZE_TYPE__ size_t; + +#define TEST_ABORT if (inside_main) abort() + +/* LTO code is at the present to able to track that asm alias my_bcopy on builtin + actually refers to this function. See PR47181. */ +__attribute__ ((used)) +void * +my_memcpy (void *d, const void *s, size_t n) +{ + char *dst = (char *) d; + const char *src = (const char *) s; + while (n--) + *dst++ = *src++; + return (char *) d; +} + +/* LTO code is at the present to able to track that asm alias my_bcopy on builtin + actually refers to this function. See PR47181. */ +__attribute__ ((used)) +void +my_bcopy (const void *s, void *d, size_t n) +{ + char *dst = (char *) d; + const char *src = (const char *) s; + if (src >= dst) + while (n--) + *dst++ = *src++; + else + { + dst += n; + src += n; + while (n--) + *--dst = *--src; + } +} + +/* LTO code is at the present to able to track that asm alias my_bcopy on builtin + actually refers to this function. See PR47181. */ +__attribute__ ((used)) +void * +my_memset (void *d, int c, size_t n) +{ + char *dst = (char *) d; + while (n--) + *dst++ = c; + return (char *) d; +} + +/* LTO code is at the present to able to track that asm alias my_bcopy on builtin + actually refers to this function. See PR47181. */ +__attribute__ ((used)) +void +my_bzero (void *d, size_t n) +{ + char *dst = (char *) d; + while (n--) + *dst++ = '\0'; +} + +void * +memcpy (void *d, const void *s, size_t n) +{ + void *result = my_memcpy (d, s, n); + TEST_ABORT; + return result; +} + +void +bcopy (const void *s, void *d, size_t n) +{ + my_bcopy (s, d, n); + TEST_ABORT; +} + +void * +memset (void *d, int c, size_t n) +{ + void *result = my_memset (d, c, n); + TEST_ABORT; + return result; +} + +void +bzero (void *d, size_t n) +{ + my_bzero (d, n); + TEST_ABORT; +} + +#ifdef __vxworks +/* The RTP C library uses bfill, which is defined in the same file as + bzero and bcopy. */ +#include "lib/bfill.c" +#endif diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memops-asm.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memops-asm.c new file mode 100644 index 000000000..ed2b06cf0 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memops-asm.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2003 Free Software Foundation. + + Test memcpy and memset in presence of redirect. */ + +#define ASMNAME(cname) ASMNAME2 (__USER_LABEL_PREFIX__, cname) +#define ASMNAME2(prefix, cname) STRING (prefix) cname +#define STRING(x) #x + +typedef __SIZE_TYPE__ size_t; +extern void abort (void); +extern void *memcpy (void *, const void *, size_t) + __asm (ASMNAME ("my_memcpy")); +extern void bcopy (const void *, void *, size_t) + __asm (ASMNAME ("my_bcopy")); +extern void *memset (void *, int, size_t) + __asm (ASMNAME ("my_memset")); +extern void bzero (void *, size_t) + __asm (ASMNAME ("my_bzero")); +extern int memcmp (const void *, const void *, size_t); + +struct A { char c[32]; } a = { "foobar" }; +char x[64] = "foobar", y[64]; +int i = 39, j = 6, k = 4; + +extern int inside_main; + +void +main_test (void) +{ + struct A b = a; + struct A c = { { 'x' } }; + + inside_main = 1; + + if (memcmp (b.c, x, 32) || c.c[0] != 'x' || memcmp (c.c + 1, x + 32, 31)) + abort (); + if (__builtin_memcpy (y, x, i) != y || memcmp (x, y, 64)) + abort (); + if (memcpy (y + 6, x, j) != y + 6 + || memcmp (x, y, 6) || memcmp (x, y + 6, 58)) + abort (); + if (__builtin_memset (y + 2, 'X', k) != y + 2 + || memcmp (y, "foXXXXfoobar", 13)) + abort (); + bcopy (y + 1, y + 2, 6); + if (memcmp (y, "fooXXXXfobar", 13)) + abort (); + __builtin_bzero (y + 4, 2); + if (memcmp (y, "fooX\0\0Xfobar", 13)) + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-2-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-2-lib.c new file mode 100644 index 000000000..cf3178c83 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-2-lib.c @@ -0,0 +1 @@ +#include "lib/mempcpy.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-2.c b/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-2.c new file mode 100644 index 000000000..3b7767acb --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-2.c @@ -0,0 +1,153 @@ +/* Copyright (C) 2003 Free Software Foundation. + + Ensure that builtin mempcpy and stpcpy perform correctly. + + Written by Jakub Jelinek, 21/05/2003. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern void *mempcpy (void *, const void *, size_t); +extern int memcmp (const void *, const void *, size_t); +extern int inside_main; + +long buf1[64]; +char *buf2 = (char *) (buf1 + 32); +long buf5[20]; +char buf7[20]; + +void +__attribute__((noinline)) +test (long *buf3, char *buf4, char *buf6, int n) +{ + int i = 0; + + /* These should probably be handled by store_by_pieces on most arches. */ + if (mempcpy (buf1, "ABCDEFGHI", 9) != (char *) buf1 + 9 + || memcmp (buf1, "ABCDEFGHI\0", 11)) + abort (); + + if (mempcpy (buf1, "abcdefghijklmnopq", 17) != (char *) buf1 + 17 + || memcmp (buf1, "abcdefghijklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy (buf3, "ABCDEF", 6) != (char *) buf1 + 6 + || memcmp (buf1, "ABCDEFghijklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy (buf3, "a", 1) != (char *) buf1 + 1 + || memcmp (buf1, "aBCDEFghijklmnopq\0", 19)) + abort (); + + if (mempcpy ((char *) buf3 + 2, "bcd" + ++i, 2) != (char *) buf1 + 4 + || memcmp (buf1, "aBcdEFghijklmnopq\0", 19) + || i != 1) + abort (); + + /* These should probably be handled by move_by_pieces on most arches. */ + if (mempcpy ((char *) buf3 + 4, buf5, 6) != (char *) buf1 + 10 + || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy ((char *) buf1 + ++i + 8, (char *) buf5 + 1, 1) + != (char *) buf1 + 11 + || memcmp (buf1, "aBcdRSTUVWSlmnopq\0", 19) + || i != 2) + abort (); + + if (mempcpy ((char *) buf3 + 14, buf6, 2) != (char *) buf1 + 16 + || memcmp (buf1, "aBcdRSTUVWSlmnrsq\0", 19)) + abort (); + + if (mempcpy (buf3, buf5, 8) != (char *) buf1 + 8 + || memcmp (buf1, "RSTUVWXYVWSlmnrsq\0", 19)) + abort (); + + if (mempcpy (buf3, buf5, 17) != (char *) buf1 + 17 + || memcmp (buf1, "RSTUVWXYZ01234567\0", 19)) + abort (); + + __builtin_memcpy (buf3, "aBcdEFghijklmnopq\0", 19); + + /* These should be handled either by movmemendM or mempcpy + call. */ + if (mempcpy ((char *) buf3 + 4, buf5, n + 6) != (char *) buf1 + 10 + || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy ((char *) buf1 + ++i + 8, (char *) buf5 + 1, n + 1) + != (char *) buf1 + 12 + || memcmp (buf1, "aBcdRSTUVWkSmnopq\0", 19) + || i != 3) + abort (); + + if (mempcpy ((char *) buf3 + 14, buf6, n + 2) != (char *) buf1 + 16 + || memcmp (buf1, "aBcdRSTUVWkSmnrsq\0", 19)) + abort (); + + i = 1; + + /* These might be handled by store_by_pieces. */ + if (mempcpy (buf2, "ABCDEFGHI", 9) != buf2 + 9 + || memcmp (buf2, "ABCDEFGHI\0", 11)) + abort (); + + if (mempcpy (buf2, "abcdefghijklmnopq", 17) != buf2 + 17 + || memcmp (buf2, "abcdefghijklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy (buf4, "ABCDEF", 6) != buf2 + 6 + || memcmp (buf2, "ABCDEFghijklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy (buf4, "a", 1) != buf2 + 1 + || memcmp (buf2, "aBCDEFghijklmnopq\0", 19)) + abort (); + + if (mempcpy (buf4 + 2, "bcd" + i++, 2) != buf2 + 4 + || memcmp (buf2, "aBcdEFghijklmnopq\0", 19) + || i != 2) + abort (); + + /* These might be handled by move_by_pieces. */ + if (mempcpy (buf4 + 4, buf7, 6) != buf2 + 10 + || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy (buf2 + i++ + 8, buf7 + 1, 1) + != buf2 + 11 + || memcmp (buf2, "aBcdRSTUVWSlmnopq\0", 19) + || i != 3) + abort (); + + if (mempcpy (buf4 + 14, buf6, 2) != buf2 + 16 + || memcmp (buf2, "aBcdRSTUVWSlmnrsq\0", 19)) + abort (); + + __builtin_memcpy (buf4, "aBcdEFghijklmnopq\0", 19); + + /* These should be handled either by movmemendM or mempcpy + call. */ + if (mempcpy (buf4 + 4, buf7, n + 6) != buf2 + 10 + || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy (buf2 + i++ + 8, buf7 + 1, n + 1) + != buf2 + 12 + || memcmp (buf2, "aBcdRSTUVWkSmnopq\0", 19) + || i != 4) + abort (); + + if (mempcpy (buf4 + 14, buf6, n + 2) != buf2 + 16 + || memcmp (buf2, "aBcdRSTUVWkSmnrsq\0", 19)) + abort (); +} + +void +main_test (void) +{ + /* All these tests are allowed to call mempcpy/stpcpy. */ + inside_main = 0; + __builtin_memcpy (buf5, "RSTUVWXYZ0123456789", 20); + __builtin_memcpy (buf7, "RSTUVWXYZ0123456789", 20); + test (buf1, buf2, "rstuvwxyz", 0); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-chk-lib.c new file mode 100644 index 000000000..9daf13e82 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-chk-lib.c @@ -0,0 +1 @@ +#include "lib/chk.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-chk.c b/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-chk.c new file mode 100644 index 000000000..7a1737c4a --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-chk.c @@ -0,0 +1,487 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation. + + Ensure builtin __mempcpy_chk performs correctly. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strlen(const char *); +extern void *memcpy (void *, const void *, size_t); +extern void *mempcpy (void *, const void *, size_t); +extern int memcmp (const void *, const void *, size_t); + +#include "chk.h" + +const char s1[] = "123"; +char p[32] = ""; +volatile char *s2 = "defg"; /* prevent constant propagation to happen when whole program assumptions are made. */ +volatile char *s3 = "FGH"; /* prevent constant propagation to happen when whole program assumptions are made. */ +volatile size_t l1 = 1; /* prevent constant propagation to happen when whole program assumptions are made. */ + +void +__attribute__((noinline)) +test1 (void) +{ + int i; + +#if defined __i386__ || defined __x86_64__ + /* The functions below might not be optimized into direct stores on all + arches. It depends on how many instructions would be generated and + what limits the architecture chooses in STORE_BY_PIECES_P. */ + mempcpy_disallowed = 1; +#endif + + /* All the mempcpy calls in this routine except last have fixed length, so + object size checking should be done at compile time if optimizing. */ + chk_calls = 0; + + if (mempcpy (p, "ABCDE", 6) != p + 6 || memcmp (p, "ABCDE", 6)) + abort (); + if (mempcpy (p + 16, "VWX" + 1, 2) != p + 16 + 2 + || memcmp (p + 16, "WX\0\0", 5)) + abort (); + if (mempcpy (p + 1, "", 1) != p + 1 + 1 || memcmp (p, "A\0CDE", 6)) + abort (); + if (mempcpy (p + 3, "FGHI", 4) != p + 3 + 4 || memcmp (p, "A\0CFGHI", 8)) + abort (); + + i = 8; + memcpy (p + 20, "qrstu", 6); + memcpy (p + 25, "QRSTU", 6); + if (mempcpy (p + 25 + 1, s1, 3) != (p + 25 + 1 + 3) + || memcmp (p + 25, "Q123U", 6)) + abort (); + + if (mempcpy (mempcpy (p, "abcdEFG", 4), "efg", 4) != p + 8 + || memcmp (p, "abcdefg", 8)) + abort(); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_mempcpy (p, "ABCDE", 6) != p + 6 || memcmp (p, "ABCDE", 6)) + abort (); + + /* If the result of mempcpy is ignored, gcc should use memcpy. + This should be optimized always, so disallow mempcpy calls. */ + mempcpy_disallowed = 1; + mempcpy (p + 5, s3, 1); + if (memcmp (p, "ABCDEFg", 8)) + abort (); + + if (chk_calls) + abort (); + chk_calls = 0; + + mempcpy (p + 6, s1 + 1, l1); + if (memcmp (p, "ABCDEF2", 8)) + abort (); + + /* The above mempcpy copies into an object with known size, but + unknown length and with result ignored, so it should be a + __memcpy_chk call. */ + if (chk_calls != 1) + abort (); + + mempcpy_disallowed = 0; +} + +long buf1[64]; +char *buf2 = (char *) (buf1 + 32); +long buf5[20]; +char buf7[20]; + +void +__attribute__((noinline)) +test2_sub (long *buf3, char *buf4, char *buf6, int n) +{ + int i = 0; + + /* All the mempcpy/__builtin_mempcpy/__builtin___mempcpy_chk + calls in this routine are either fixed length, or have + side-effects in __builtin_object_size arguments, or + dst doesn't point into a known object. */ + chk_calls = 0; + + /* These should probably be handled by store_by_pieces on most arches. */ + if (mempcpy (buf1, "ABCDEFGHI", 9) != (char *) buf1 + 9 + || memcmp (buf1, "ABCDEFGHI\0", 11)) + abort (); + + if (mempcpy (buf1, "abcdefghijklmnopq", 17) != (char *) buf1 + 17 + || memcmp (buf1, "abcdefghijklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy (buf3, "ABCDEF", 6) != (char *) buf1 + 6 + || memcmp (buf1, "ABCDEFghijklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy (buf3, "a", 1) != (char *) buf1 + 1 + || memcmp (buf1, "aBCDEFghijklmnopq\0", 19)) + abort (); + + if (mempcpy ((char *) buf3 + 2, "bcd" + ++i, 2) != (char *) buf1 + 4 + || memcmp (buf1, "aBcdEFghijklmnopq\0", 19) + || i != 1) + abort (); + + /* These should probably be handled by move_by_pieces on most arches. */ + if (mempcpy ((char *) buf3 + 4, buf5, 6) != (char *) buf1 + 10 + || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy ((char *) buf1 + ++i + 8, (char *) buf5 + 1, 1) + != (char *) buf1 + 11 + || memcmp (buf1, "aBcdRSTUVWSlmnopq\0", 19) + || i != 2) + abort (); + + if (mempcpy ((char *) buf3 + 14, buf6, 2) != (char *) buf1 + 16 + || memcmp (buf1, "aBcdRSTUVWSlmnrsq\0", 19)) + abort (); + + if (mempcpy (buf3, buf5, 8) != (char *) buf1 + 8 + || memcmp (buf1, "RSTUVWXYVWSlmnrsq\0", 19)) + abort (); + + if (mempcpy (buf3, buf5, 17) != (char *) buf1 + 17 + || memcmp (buf1, "RSTUVWXYZ01234567\0", 19)) + abort (); + + __builtin_memcpy (buf3, "aBcdEFghijklmnopq\0", 19); + + /* These should be handled either by movmemendM or mempcpy + call. */ + + /* buf3 points to an unknown object, so __mempcpy_chk should not be done. */ + if (mempcpy ((char *) buf3 + 4, buf5, n + 6) != (char *) buf1 + 10 + || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + /* This call has side-effects in dst, therefore no checking. */ + if (__builtin___mempcpy_chk ((char *) buf1 + ++i + 8, (char *) buf5 + 1, + n + 1, os ((char *) buf1 + ++i + 8)) + != (char *) buf1 + 12 + || memcmp (buf1, "aBcdRSTUVWkSmnopq\0", 19) + || i != 3) + abort (); + + if (mempcpy ((char *) buf3 + 14, buf6, n + 2) != (char *) buf1 + 16 + || memcmp (buf1, "aBcdRSTUVWkSmnrsq\0", 19)) + abort (); + + i = 1; + + /* These might be handled by store_by_pieces. */ + if (mempcpy (buf2, "ABCDEFGHI", 9) != buf2 + 9 + || memcmp (buf2, "ABCDEFGHI\0", 11)) + abort (); + + if (mempcpy (buf2, "abcdefghijklmnopq", 17) != buf2 + 17 + || memcmp (buf2, "abcdefghijklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy (buf4, "ABCDEF", 6) != buf2 + 6 + || memcmp (buf2, "ABCDEFghijklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy (buf4, "a", 1) != buf2 + 1 + || memcmp (buf2, "aBCDEFghijklmnopq\0", 19)) + abort (); + + if (mempcpy (buf4 + 2, "bcd" + i++, 2) != buf2 + 4 + || memcmp (buf2, "aBcdEFghijklmnopq\0", 19) + || i != 2) + abort (); + + /* These might be handled by move_by_pieces. */ + if (mempcpy (buf4 + 4, buf7, 6) != buf2 + 10 + || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + /* Side effect. */ + if (__builtin___mempcpy_chk (buf2 + i++ + 8, buf7 + 1, 1, + os (buf2 + i++ + 8)) + != buf2 + 11 + || memcmp (buf2, "aBcdRSTUVWSlmnopq\0", 19) + || i != 3) + abort (); + + if (mempcpy (buf4 + 14, buf6, 2) != buf2 + 16 + || memcmp (buf2, "aBcdRSTUVWSlmnrsq\0", 19)) + abort (); + + __builtin_memcpy (buf4, "aBcdEFghijklmnopq\0", 19); + + /* These should be handled either by movmemendM or mempcpy + call. */ + if (mempcpy (buf4 + 4, buf7, n + 6) != buf2 + 10 + || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + /* Side effect. */ + if (__builtin___mempcpy_chk (buf2 + i++ + 8, buf7 + 1, + n + 1, os (buf2 + i++ + 8)) + != buf2 + 12 + || memcmp (buf2, "aBcdRSTUVWkSmnopq\0", 19) + || i != 4) + abort (); + + if (mempcpy (buf4 + 14, buf6, n + 2) != buf2 + 16 + || memcmp (buf2, "aBcdRSTUVWkSmnrsq\0", 19)) + abort (); + + if (chk_calls) + abort (); +} + +void +__attribute__((noinline)) +test2 (void) +{ + long *x; + char *y; + int z; + __builtin_memcpy (buf5, "RSTUVWXYZ0123456789", 20); + __builtin_memcpy (buf7, "RSTUVWXYZ0123456789", 20); + __asm ("" : "=r" (x) : "0" (buf1)); + __asm ("" : "=r" (y) : "0" (buf2)); + __asm ("" : "=r" (z) : "0" (0)); + test2_sub (x, y, "rstuvwxyz", z); +} + +volatile void *vx; + +/* Test whether compile time checking is done where it should + and so is runtime object size checking. */ +void +__attribute__((noinline)) +test3 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4]; + char buf3[20]; + int i; + size_t l; + + /* The following calls should do runtime checking + - length is not known, but destination is. */ + chk_calls = 0; + vx = mempcpy (a.buf1 + 2, s3, l1); + vx = mempcpy (r, s3, l1 + 1); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + vx = mempcpy (r, s2, l1 + 2); + vx = mempcpy (r + 2, s3, l1); + r = buf3; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1]; + else if (i == l1) + r = &a.buf2[7]; + else if (i == l1 + 1) + r = &buf3[5]; + else if (i == l1 + 2) + r = &a.buf1[9]; + } + vx = mempcpy (r, s2, l1); + if (chk_calls != 5) + abort (); + + /* Following have known destination and known length, + so if optimizing certainly shouldn't result in the checking + variants. */ + chk_calls = 0; + vx = mempcpy (a.buf1 + 2, s3, 1); + vx = mempcpy (r, s3, 2); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + vx = mempcpy (r, s2, 3); + r = buf3; + l = 4; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1], l = 2; + else if (i == l1) + r = &a.buf2[7], l = 3; + else if (i == l1 + 1) + r = &buf3[5], l = 4; + else if (i == l1 + 2) + r = &a.buf1[9], l = 1; + } + vx = mempcpy (r, s2, 1); + /* Here, l is known to be at most 4 and __builtin_object_size (&buf3[16], 0) + is 4, so this doesn't need runtime checking. */ + vx = mempcpy (&buf3[16], s2, l); + if (chk_calls) + abort (); + chk_calls = 0; +} + +/* Test whether runtime and/or compile time checking catches + buffer overflows. */ +void +__attribute__((noinline)) +test4 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char buf3[20]; + + chk_fail_allowed = 1; + /* Runtime checks. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + vx = mempcpy (&a.buf2[9], s2, l1 + 1); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + vx = mempcpy (&a.buf2[7], s3, strlen (s3) + 1); + abort (); + } + /* This should be detectable at compile time already. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + vx = mempcpy (&buf3[19], "ab", 2); + abort (); + } + chk_fail_allowed = 0; +} + +#ifndef MAX_OFFSET +#define MAX_OFFSET (sizeof (long long)) +#endif + +#ifndef MAX_COPY +#define MAX_COPY (10 * sizeof (long long)) +#endif + +#ifndef MAX_EXTRA +#define MAX_EXTRA (sizeof (long long)) +#endif + +#define MAX_LENGTH (MAX_OFFSET + MAX_COPY + MAX_EXTRA) + +/* Use a sequence length that is not divisible by two, to make it more + likely to detect when words are mixed up. */ +#define SEQUENCE_LENGTH 31 + +static union { + char buf[MAX_LENGTH]; + long long align_int; + long double align_fp; +} u1, u2; + +void +__attribute__((noinline)) +test5 (void) +{ + int off1, off2, len, i; + char *p, *q, c; + + for (off1 = 0; off1 < MAX_OFFSET; off1++) + for (off2 = 0; off2 < MAX_OFFSET; off2++) + for (len = 1; len < MAX_COPY; len++) + { + for (i = 0, c = 'A'; i < MAX_LENGTH; i++, c++) + { + u1.buf[i] = 'a'; + if (c >= 'A' + SEQUENCE_LENGTH) + c = 'A'; + u2.buf[i] = c; + } + + p = mempcpy (u1.buf + off1, u2.buf + off2, len); + if (p != u1.buf + off1 + len) + abort (); + + q = u1.buf; + for (i = 0; i < off1; i++, q++) + if (*q != 'a') + abort (); + + for (i = 0, c = 'A' + off2; i < len; i++, q++, c++) + { + if (c >= 'A' + SEQUENCE_LENGTH) + c = 'A'; + if (*q != c) + abort (); + } + + for (i = 0; i < MAX_EXTRA; i++, q++) + if (*q != 'a') + abort (); + } +} + +#define TESTSIZE 80 + +char srcb[TESTSIZE] __attribute__ ((aligned)); +char dstb[TESTSIZE] __attribute__ ((aligned)); + +void +__attribute__((noinline)) +check (char *test, char *match, int n) +{ + if (memcmp (test, match, n)) + abort (); +} + +#define TN(n) \ +{ memset (dstb, 0, n); vx = mempcpy (dstb, srcb, n); check (dstb, srcb, n); } +#define T(n) \ +TN (n) \ +TN ((n) + 1) \ +TN ((n) + 2) \ +TN ((n) + 3) + +void +__attribute__((noinline)) +test6 (void) +{ + int i; + + chk_calls = 0; + + for (i = 0; i < sizeof (srcb); ++i) + srcb[i] = 'a' + i % 26; + + T (0); + T (4); + T (8); + T (12); + T (16); + T (20); + T (24); + T (28); + T (32); + T (36); + T (40); + T (44); + T (48); + T (52); + T (56); + T (60); + T (64); + T (68); + T (72); + T (76); + + /* All mempcpy calls in this routine have constant arguments. */ + if (chk_calls) + abort (); +} + +void +main_test (void) +{ +#ifndef __OPTIMIZE__ + /* Object size checking is only intended for -O[s123]. */ + return; +#endif + __asm ("" : "=r" (l1) : "0" (l1)); + test1 (); + test2 (); + test3 (); + test4 (); + test5 (); + test6 (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-lib.c new file mode 100644 index 000000000..cf3178c83 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-lib.c @@ -0,0 +1 @@ +#include "lib/mempcpy.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy.c b/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy.c new file mode 100644 index 000000000..d82e2232d --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy.c @@ -0,0 +1,68 @@ +/* Copyright (C) 2003 Free Software Foundation. + + Ensure builtin mempcpy performs correctly. + + Written by Kaveh Ghazi, 4/11/2003. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strlen(const char *); +extern void *memcpy (void *, const void *, size_t); +extern void *mempcpy (void *, const void *, size_t); +extern int memcmp (const void *, const void *, size_t); +extern int inside_main; + +const char s1[] = "123"; +char p[32] = ""; +char *s2 = "defg"; +char *s3 = "FGH"; +size_t l1 = 1; + +void +main_test (void) +{ + int i; + +#if !defined __i386__ && !defined __x86_64__ + /* The functions below might not be optimized into direct stores on all + arches. It depends on how many instructions would be generated and + what limits the architecture chooses in STORE_BY_PIECES_P. */ + inside_main = 0; +#endif + + if (mempcpy (p, "ABCDE", 6) != p + 6 || memcmp (p, "ABCDE", 6)) + abort (); + if (mempcpy (p + 16, "VWX" + 1, 2) != p + 16 + 2 + || memcmp (p + 16, "WX\0\0", 5)) + abort (); + if (mempcpy (p + 1, "", 1) != p + 1 + 1 || memcmp (p, "A\0CDE", 6)) + abort (); + if (mempcpy (p + 3, "FGHI", 4) != p + 3 + 4 || memcmp (p, "A\0CFGHI", 8)) + abort (); + + i = 8; + memcpy (p + 20, "qrstu", 6); + memcpy (p + 25, "QRSTU", 6); + if (mempcpy (p + 25 + 1, s1, 3) != (p + 25 + 1 + 3) + || memcmp (p + 25, "Q123U", 6)) + abort (); + + if (mempcpy (mempcpy (p, "abcdEFG", 4), "efg", 4) != p + 8 + || memcmp (p, "abcdefg", 8)) + abort(); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_mempcpy (p, "ABCDE", 6) != p + 6 || memcmp (p, "ABCDE", 6)) + abort (); + + /* If the result of mempcpy is ignored, gcc should use memcpy. + This should be optimized always, so set inside_main again. */ + inside_main = 1; + mempcpy (p + 5, s3, 1); + if (memcmp (p, "ABCDEFg", 8)) + abort (); + mempcpy (p + 6, s1 + 1, l1); + if (memcmp (p, "ABCDEF2", 8)) + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memset-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memset-chk-lib.c new file mode 100644 index 000000000..9daf13e82 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memset-chk-lib.c @@ -0,0 +1 @@ +#include "lib/chk.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memset-chk.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memset-chk.c new file mode 100644 index 000000000..902a88503 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memset-chk.c @@ -0,0 +1,721 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation. + + Ensure builtin __memset_chk performs correctly. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strlen(const char *); +extern void *memcpy (void *, const void *, size_t); +extern void *memset (void *, int, size_t); +extern int memcmp (const void *, const void *, size_t); + +#include "chk.h" + +char buffer[32]; +int argc = 1; +volatile size_t l1 = 1; /* prevent constant propagation to happen when whole program assumptions are made. */ +volatile char *s3 = "FGH"; /* prevent constant propagation to happen when whole program assumptions are made. */ +char *s4; + +void +__attribute__((noinline)) +test1 (void) +{ + memset_disallowed = 1; + chk_calls = 0; + memset (buffer, argc, 0); + memset (buffer, argc, 1); + memset (buffer, argc, 2); + memset (buffer, argc, 3); + memset (buffer, argc, 4); + memset (buffer, argc, 5); + memset (buffer, argc, 6); + memset (buffer, argc, 7); + memset (buffer, argc, 8); + memset (buffer, argc, 9); + memset (buffer, argc, 10); + memset (buffer, argc, 11); + memset (buffer, argc, 12); + memset (buffer, argc, 13); + memset (buffer, argc, 14); + memset (buffer, argc, 15); + memset (buffer, argc, 16); + memset (buffer, argc, 17); + memset_disallowed = 0; + if (chk_calls) + abort (); +} + +/* Test whether compile time checking is done where it should + and so is runtime object size checking. */ +void +__attribute__((noinline)) +test2 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4]; + char buf3[20]; + int i; + size_t l; + + /* The following calls should do runtime checking + - length is not known, but destination is. */ + chk_calls = 0; + memset (a.buf1 + 2, 'a', l1); + memset (r, '\0', l1 + 1); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + memset (r, argc, l1 + 2); + memset (r + 2, 'Q', l1); + r = buf3; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1]; + else if (i == l1) + r = &a.buf2[7]; + else if (i == l1 + 1) + r = &buf3[5]; + else if (i == l1 + 2) + r = &a.buf1[9]; + } + memset (r, '\0', l1); + if (chk_calls != 5) + abort (); + + /* Following have known destination and known length, + so if optimizing certainly shouldn't result in the checking + variants. */ + chk_calls = 0; + memset (a.buf1 + 2, '\0', 1); + memset (r, argc, 2); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + memset (r, 'N', 3); + r = buf3; + l = 4; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1], l = 2; + else if (i == l1) + r = &a.buf2[7], l = 3; + else if (i == l1 + 1) + r = &buf3[5], l = 4; + else if (i == l1 + 2) + r = &a.buf1[9], l = 1; + } + memset (r, 'H', 1); + /* Here, l is known to be at most 4 and __builtin_object_size (&buf3[16], 0) + is 4, so this doesn't need runtime checking. */ + memset (&buf3[16], 'd', l); + /* Neither length nor destination known. Doesn't need runtime checking. */ + memset (s4, 'a', l1); + memset (s4 + 2, '\0', l1 + 2); + /* Destination unknown. */ + memset (s4 + 4, 'b', 2); + memset (s4 + 6, '\0', 4); + if (chk_calls) + abort (); + chk_calls = 0; +} + +/* Test whether runtime and/or compile time checking catches + buffer overflows. */ +void +__attribute__((noinline)) +test3 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char buf3[20]; + + chk_fail_allowed = 1; + /* Runtime checks. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + memset (&a.buf2[9], '\0', l1 + 1); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + memset (&a.buf2[7], 'T', strlen (s3) + 1); + abort (); + } + /* This should be detectable at compile time already. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + memset (&buf3[19], 'b', 2); + abort (); + } + chk_fail_allowed = 0; +} + +#ifndef MAX_OFFSET +#define MAX_OFFSET (sizeof (long long)) +#endif + +#ifndef MAX_COPY +#define MAX_COPY (10 * sizeof (long long)) +#define MAX_COPY2 15 +#else +#define MAX_COPY2 MAX_COPY +#endif + +#ifndef MAX_EXTRA +#define MAX_EXTRA (sizeof (long long)) +#endif + +#define MAX_LENGTH (MAX_OFFSET + MAX_COPY + MAX_EXTRA) +#define MAX_LENGTH2 (MAX_OFFSET + MAX_COPY2 + MAX_EXTRA) + +static union { + char buf[MAX_LENGTH]; + long long align_int; + long double align_fp; +} u; + +char A = 'A'; + +void +__attribute__((noinline)) +test4 (void) +{ + int off, len, i; + char *p, *q; + + for (off = 0; off < MAX_OFFSET; off++) + for (len = 1; len < MAX_COPY; len++) + { + for (i = 0; i < MAX_LENGTH; i++) + u.buf[i] = 'a'; + + p = memset (u.buf + off, '\0', len); + if (p != u.buf + off) + abort (); + + q = u.buf; + for (i = 0; i < off; i++, q++) + if (*q != 'a') + abort (); + + for (i = 0; i < len; i++, q++) + if (*q != '\0') + abort (); + + for (i = 0; i < MAX_EXTRA; i++, q++) + if (*q != 'a') + abort (); + + p = memset (u.buf + off, A, len); + if (p != u.buf + off) + abort (); + + q = u.buf; + for (i = 0; i < off; i++, q++) + if (*q != 'a') + abort (); + + for (i = 0; i < len; i++, q++) + if (*q != 'A') + abort (); + + for (i = 0; i < MAX_EXTRA; i++, q++) + if (*q != 'a') + abort (); + + p = memset (u.buf + off, 'B', len); + if (p != u.buf + off) + abort (); + + q = u.buf; + for (i = 0; i < off; i++, q++) + if (*q != 'a') + abort (); + + for (i = 0; i < len; i++, q++) + if (*q != 'B') + abort (); + + for (i = 0; i < MAX_EXTRA; i++, q++) + if (*q != 'a') + abort (); + } +} + +static union { + char buf[MAX_LENGTH2]; + long long align_int; + long double align_fp; +} u2; + +void reset () +{ + int i; + + for (i = 0; i < MAX_LENGTH2; i++) + u2.buf[i] = 'a'; +} + +void check (int off, int len, int ch) +{ + char *q; + int i; + + q = u2.buf; + for (i = 0; i < off; i++, q++) + if (*q != 'a') + abort (); + + for (i = 0; i < len; i++, q++) + if (*q != ch) + abort (); + + for (i = 0; i < MAX_EXTRA; i++, q++) + if (*q != 'a') + abort (); +} + +void +__attribute__((noinline)) +test5 (void) +{ + int off; + char *p; + + /* len == 1 */ + for (off = 0; off < MAX_OFFSET; off++) + { + reset (); + + p = memset (u2.buf + off, '\0', 1); + if (p != u2.buf + off) abort (); + check (off, 1, '\0'); + + p = memset (u2.buf + off, A, 1); + if (p != u2.buf + off) abort (); + check (off, 1, 'A'); + + p = memset (u2.buf + off, 'B', 1); + if (p != u2.buf + off) abort (); + check (off, 1, 'B'); + } + + /* len == 2 */ + for (off = 0; off < MAX_OFFSET; off++) + { + reset (); + + p = memset (u2.buf + off, '\0', 2); + if (p != u2.buf + off) abort (); + check (off, 2, '\0'); + + p = memset (u2.buf + off, A, 2); + if (p != u2.buf + off) abort (); + check (off, 2, 'A'); + + p = memset (u2.buf + off, 'B', 2); + if (p != u2.buf + off) abort (); + check (off, 2, 'B'); + } + + /* len == 3 */ + for (off = 0; off < MAX_OFFSET; off++) + { + reset (); + + p = memset (u2.buf + off, '\0', 3); + if (p != u2.buf + off) abort (); + check (off, 3, '\0'); + + p = memset (u2.buf + off, A, 3); + if (p != u2.buf + off) abort (); + check (off, 3, 'A'); + + p = memset (u2.buf + off, 'B', 3); + if (p != u2.buf + off) abort (); + check (off, 3, 'B'); + } + + /* len == 4 */ + for (off = 0; off < MAX_OFFSET; off++) + { + reset (); + + p = memset (u2.buf + off, '\0', 4); + if (p != u2.buf + off) abort (); + check (off, 4, '\0'); + + p = memset (u2.buf + off, A, 4); + if (p != u2.buf + off) abort (); + check (off, 4, 'A'); + + p = memset (u2.buf + off, 'B', 4); + if (p != u2.buf + off) abort (); + check (off, 4, 'B'); + } + + /* len == 5 */ + for (off = 0; off < MAX_OFFSET; off++) + { + reset (); + + p = memset (u2.buf + off, '\0', 5); + if (p != u2.buf + off) abort (); + check (off, 5, '\0'); + + p = memset (u2.buf + off, A, 5); + if (p != u2.buf + off) abort (); + check (off, 5, 'A'); + + p = memset (u2.buf + off, 'B', 5); + if (p != u2.buf + off) abort (); + check (off, 5, 'B'); + } + + /* len == 6 */ + for (off = 0; off < MAX_OFFSET; off++) + { + reset (); + + p = memset (u2.buf + off, '\0', 6); + if (p != u2.buf + off) abort (); + check (off, 6, '\0'); + + p = memset (u2.buf + off, A, 6); + if (p != u2.buf + off) abort (); + check (off, 6, 'A'); + + p = memset (u2.buf + off, 'B', 6); + if (p != u2.buf + off) abort (); + check (off, 6, 'B'); + } + + /* len == 7 */ + for (off = 0; off < MAX_OFFSET; off++) + { + reset (); + + p = memset (u2.buf + off, '\0', 7); + if (p != u2.buf + off) abort (); + check (off, 7, '\0'); + + p = memset (u2.buf + off, A, 7); + if (p != u2.buf + off) abort (); + check (off, 7, 'A'); + + p = memset (u2.buf + off, 'B', 7); + if (p != u2.buf + off) abort (); + check (off, 7, 'B'); + } + + /* len == 8 */ + for (off = 0; off < MAX_OFFSET; off++) + { + reset (); + + p = memset (u2.buf + off, '\0', 8); + if (p != u2.buf + off) abort (); + check (off, 8, '\0'); + + p = memset (u2.buf + off, A, 8); + if (p != u2.buf + off) abort (); + check (off, 8, 'A'); + + p = memset (u2.buf + off, 'B', 8); + if (p != u2.buf + off) abort (); + check (off, 8, 'B'); + } + + /* len == 9 */ + for (off = 0; off < MAX_OFFSET; off++) + { + reset (); + + p = memset (u2.buf + off, '\0', 9); + if (p != u2.buf + off) abort (); + check (off, 9, '\0'); + + p = memset (u2.buf + off, A, 9); + if (p != u2.buf + off) abort (); + check (off, 9, 'A'); + + p = memset (u2.buf + off, 'B', 9); + if (p != u2.buf + off) abort (); + check (off, 9, 'B'); + } + + /* len == 10 */ + for (off = 0; off < MAX_OFFSET; off++) + { + reset (); + + p = memset (u2.buf + off, '\0', 10); + if (p != u2.buf + off) abort (); + check (off, 10, '\0'); + + p = memset (u2.buf + off, A, 10); + if (p != u2.buf + off) abort (); + check (off, 10, 'A'); + + p = memset (u2.buf + off, 'B', 10); + if (p != u2.buf + off) abort (); + check (off, 10, 'B'); + } + + /* len == 11 */ + for (off = 0; off < MAX_OFFSET; off++) + { + reset (); + + p = memset (u2.buf + off, '\0', 11); + if (p != u2.buf + off) abort (); + check (off, 11, '\0'); + + p = memset (u2.buf + off, A, 11); + if (p != u2.buf + off) abort (); + check (off, 11, 'A'); + + p = memset (u2.buf + off, 'B', 11); + if (p != u2.buf + off) abort (); + check (off, 11, 'B'); + } + + /* len == 12 */ + for (off = 0; off < MAX_OFFSET; off++) + { + reset (); + + p = memset (u2.buf + off, '\0', 12); + if (p != u2.buf + off) abort (); + check (off, 12, '\0'); + + p = memset (u2.buf + off, A, 12); + if (p != u2.buf + off) abort (); + check (off, 12, 'A'); + + p = memset (u2.buf + off, 'B', 12); + if (p != u2.buf + off) abort (); + check (off, 12, 'B'); + } + + /* len == 13 */ + for (off = 0; off < MAX_OFFSET; off++) + { + reset (); + + p = memset (u2.buf + off, '\0', 13); + if (p != u2.buf + off) abort (); + check (off, 13, '\0'); + + p = memset (u2.buf + off, A, 13); + if (p != u2.buf + off) abort (); + check (off, 13, 'A'); + + p = memset (u2.buf + off, 'B', 13); + if (p != u2.buf + off) abort (); + check (off, 13, 'B'); + } + + /* len == 14 */ + for (off = 0; off < MAX_OFFSET; off++) + { + reset (); + + p = memset (u2.buf + off, '\0', 14); + if (p != u2.buf + off) abort (); + check (off, 14, '\0'); + + p = memset (u2.buf + off, A, 14); + if (p != u2.buf + off) abort (); + check (off, 14, 'A'); + + p = memset (u2.buf + off, 'B', 14); + if (p != u2.buf + off) abort (); + check (off, 14, 'B'); + } + + /* len == 15 */ + for (off = 0; off < MAX_OFFSET; off++) + { + reset (); + + p = memset (u2.buf + off, '\0', 15); + if (p != u2.buf + off) abort (); + check (off, 15, '\0'); + + p = memset (u2.buf + off, A, 15); + if (p != u2.buf + off) abort (); + check (off, 15, 'A'); + + p = memset (u2.buf + off, 'B', 15); + if (p != u2.buf + off) abort (); + check (off, 15, 'B'); + } +} + +void +__attribute__((noinline)) +test6 (void) +{ + int len; + char *p; + + /* off == 0 */ + for (len = 0; len < MAX_COPY2; len++) + { + reset (); + + p = memset (u2.buf, '\0', len); + if (p != u2.buf) abort (); + check (0, len, '\0'); + + p = memset (u2.buf, A, len); + if (p != u2.buf) abort (); + check (0, len, 'A'); + + p = memset (u2.buf, 'B', len); + if (p != u2.buf) abort (); + check (0, len, 'B'); + } + + /* off == 1 */ + for (len = 0; len < MAX_COPY2; len++) + { + reset (); + + p = memset (u2.buf+1, '\0', len); + if (p != u2.buf+1) abort (); + check (1, len, '\0'); + + p = memset (u2.buf+1, A, len); + if (p != u2.buf+1) abort (); + check (1, len, 'A'); + + p = memset (u2.buf+1, 'B', len); + if (p != u2.buf+1) abort (); + check (1, len, 'B'); + } + + /* off == 2 */ + for (len = 0; len < MAX_COPY2; len++) + { + reset (); + + p = memset (u2.buf+2, '\0', len); + if (p != u2.buf+2) abort (); + check (2, len, '\0'); + + p = memset (u2.buf+2, A, len); + if (p != u2.buf+2) abort (); + check (2, len, 'A'); + + p = memset (u2.buf+2, 'B', len); + if (p != u2.buf+2) abort (); + check (2, len, 'B'); + } + + /* off == 3 */ + for (len = 0; len < MAX_COPY2; len++) + { + reset (); + + p = memset (u2.buf+3, '\0', len); + if (p != u2.buf+3) abort (); + check (3, len, '\0'); + + p = memset (u2.buf+3, A, len); + if (p != u2.buf+3) abort (); + check (3, len, 'A'); + + p = memset (u2.buf+3, 'B', len); + if (p != u2.buf+3) abort (); + check (3, len, 'B'); + } + + /* off == 4 */ + for (len = 0; len < MAX_COPY2; len++) + { + reset (); + + p = memset (u2.buf+4, '\0', len); + if (p != u2.buf+4) abort (); + check (4, len, '\0'); + + p = memset (u2.buf+4, A, len); + if (p != u2.buf+4) abort (); + check (4, len, 'A'); + + p = memset (u2.buf+4, 'B', len); + if (p != u2.buf+4) abort (); + check (4, len, 'B'); + } + + /* off == 5 */ + for (len = 0; len < MAX_COPY2; len++) + { + reset (); + + p = memset (u2.buf+5, '\0', len); + if (p != u2.buf+5) abort (); + check (5, len, '\0'); + + p = memset (u2.buf+5, A, len); + if (p != u2.buf+5) abort (); + check (5, len, 'A'); + + p = memset (u2.buf+5, 'B', len); + if (p != u2.buf+5) abort (); + check (5, len, 'B'); + } + + /* off == 6 */ + for (len = 0; len < MAX_COPY2; len++) + { + reset (); + + p = memset (u2.buf+6, '\0', len); + if (p != u2.buf+6) abort (); + check (6, len, '\0'); + + p = memset (u2.buf+6, A, len); + if (p != u2.buf+6) abort (); + check (6, len, 'A'); + + p = memset (u2.buf+6, 'B', len); + if (p != u2.buf+6) abort (); + check (6, len, 'B'); + } + + /* off == 7 */ + for (len = 0; len < MAX_COPY2; len++) + { + reset (); + + p = memset (u2.buf+7, '\0', len); + if (p != u2.buf+7) abort (); + check (7, len, '\0'); + + p = memset (u2.buf+7, A, len); + if (p != u2.buf+7) abort (); + check (7, len, 'A'); + + p = memset (u2.buf+7, 'B', len); + if (p != u2.buf+7) abort (); + check (7, len, 'B'); + } +} + +void +main_test (void) +{ +#ifndef __OPTIMIZE__ + /* Object size checking is only intended for -O[s123]. */ + return; +#endif + __asm ("" : "=r" (l1) : "0" (l1)); + s4 = buffer; + test1 (); + test2 (); + test3 (); + test4 (); + test5 (); + test6 (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memset-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memset-lib.c new file mode 100644 index 000000000..2eeff38be --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memset-lib.c @@ -0,0 +1 @@ +#include "lib/memset.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memset.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memset.c new file mode 100644 index 000000000..cf7c1e303 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memset.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation. + + Ensure that builtin memset operations for constant length and + non-constant assigned value don't cause compiler problems. + + Written by Roger Sayle, 21 April 2002. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern void *memset (void *, int, size_t); + +char buffer[32]; +int argc = 1; + +void +main_test (void) +{ + memset (buffer, argc, 0); + memset (buffer, argc, 1); + memset (buffer, argc, 2); + memset (buffer, argc, 3); + memset (buffer, argc, 4); + memset (buffer, argc, 5); + memset (buffer, argc, 6); + memset (buffer, argc, 7); + memset (buffer, argc, 8); + memset (buffer, argc, 9); + memset (buffer, argc, 10); + memset (buffer, argc, 11); + memset (buffer, argc, 12); + memset (buffer, argc, 13); + memset (buffer, argc, 14); + memset (buffer, argc, 15); + memset (buffer, argc, 16); + memset (buffer, argc, 17); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/pr22237-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/pr22237-lib.c new file mode 100644 index 000000000..440323574 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/pr22237-lib.c @@ -0,0 +1,27 @@ +extern void abort (void); + +void * +memcpy (void *dst, const void *src, __SIZE_TYPE__ n) +{ + const char *srcp; + char *dstp; + + srcp = src; + dstp = dst; + + if (dst < src) + { + if (dst + n > src) + abort (); + } + else + { + if (src + n > dst) + abort (); + } + + while (n-- != 0) + *dstp++ = *srcp++; + + return dst; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/pr22237.c b/gcc/testsuite/gcc.c-torture/execute/builtins/pr22237.c new file mode 100644 index 000000000..957a47c0f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/pr22237.c @@ -0,0 +1,44 @@ +extern void abort (void); +extern void exit (int); +struct s { unsigned char a[256]; }; +union u { struct { struct s b; int c; } d; struct { int c; struct s b; } e; }; +static union u v; +static union u v0; +static struct s *p = &v.d.b; +static struct s *q = &v.e.b; + +static inline struct s rp (void) { return *p; } +static inline struct s rq (void) { return *q; } +static void pq (void) { *p = rq(); } +static void qp (void) { *q = rp(); } + +static void +init (struct s *sp) +{ + int i; + for (i = 0; i < 256; i++) + sp->a[i] = i; +} + +static void +check (struct s *sp) +{ + int i; + for (i = 0; i < 256; i++) + if (sp->a[i] != i) + abort (); +} + +void +main_test (void) +{ + v = v0; + init (p); + qp (); + check (q); + v = v0; + init (q); + pq (); + check (p); + exit (0); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/pr23484-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/pr23484-chk-lib.c new file mode 100644 index 000000000..9daf13e82 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/pr23484-chk-lib.c @@ -0,0 +1 @@ +#include "lib/chk.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/pr23484-chk.c b/gcc/testsuite/gcc.c-torture/execute/builtins/pr23484-chk.c new file mode 100644 index 000000000..446fb6c2f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/pr23484-chk.c @@ -0,0 +1,67 @@ +/* PR middle-end/23484 */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strlen (const char *); +extern void *memcpy (void *, const void *, size_t); +extern void *mempcpy (void *, const void *, size_t); +extern void *memmove (void *, const void *, size_t); +extern int snprintf (char *, size_t, const char *, ...); +extern int memcmp (const void *, const void *, size_t); + +#include "chk.h" + +static char data[8] = "ABCDEFG"; + +int l1; + +void +__attribute__((noinline)) +test1 (void) +{ + char buf[8]; + + /* All the checking calls in this routine have a maximum length, so + object size checking should be done at compile time if optimizing. */ + chk_calls = 0; + + memset (buf, 'I', sizeof (buf)); + if (memcpy (buf, data, l1 ? sizeof (buf) : 4) != buf + || memcmp (buf, "ABCDIIII", 8)) + abort (); + + memset (buf, 'J', sizeof (buf)); + if (mempcpy (buf, data, l1 ? sizeof (buf) : 4) != buf + 4 + || memcmp (buf, "ABCDJJJJ", 8)) + abort (); + + memset (buf, 'K', sizeof (buf)); + if (memmove (buf, data, l1 ? sizeof (buf) : 4) != buf + || memcmp (buf, "ABCDKKKK", 8)) + abort (); + + memset (buf, 'L', sizeof (buf)); +#if(__SIZEOF_INT__ >= 4) + if (snprintf (buf, l1 ? sizeof (buf) : 4, "%d", l1 + 65536) != 5 + || memcmp (buf, "655\0LLLL", 8)) + abort (); +#else + if (snprintf (buf, l1 ? sizeof (buf) : 4, "%d", l1 + 32700) != 5 + || memcmp (buf, "327\0LLLL", 8)) + abort (); +#endif + + if (chk_calls) + abort (); +} + +void +main_test (void) +{ +#ifndef __OPTIMIZE__ + /* Object size checking is only intended for -O[s123]. */ + return; +#endif + __asm ("" : "=r" (l1) : "0" (l1)); + test1 (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/printf-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/printf-lib.c new file mode 100644 index 000000000..45ed7ec37 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/printf-lib.c @@ -0,0 +1 @@ +#include "lib/printf.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/printf.c b/gcc/testsuite/gcc.c-torture/execute/builtins/printf.c new file mode 100644 index 000000000..e493f90b7 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/printf.c @@ -0,0 +1,52 @@ +/* Copyright (C) 2000 Free Software Foundation. + + Ensure all expected transformations of builtin printf occur and + that we honor side effects in the arguments. + + Written by Kaveh R. Ghazi, 12/4/2000. */ + +extern int printf (const char *, ...); +extern int printf_unlocked (const char *, ...); +extern void abort(void); + +void +main_test (void) +{ + const char *const s1 = "hello world"; + const char *const s2[] = { s1, 0 }, *const*s3; + + printf ("%s\n", "hello"); + printf ("%s\n", *s2); + s3 = s2; + printf ("%s\n", *s3++); + if (s3 != s2+1 || *s3 != 0) + abort(); + + printf ("%c", '\n'); + printf ("%c", **s2); + s3 = s2; + printf ("%c", **s3++); + if (s3 != s2+1 || *s3 != 0) + abort(); + + printf (""); + printf ("%s", ""); + printf ("\n"); + printf ("%s", "\n"); + printf ("hello world\n"); + printf ("%s", "hello world\n"); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + __builtin_printf ("%s\n", "hello"); + /* These builtin stubs are called by __builtin_printf, ensure their + prototypes are set correctly too. */ + __builtin_putchar ('\n'); + __builtin_puts ("hello"); + /* Check the unlocked style, these evaluate to nothing to avoid + problems on systems without the unlocked functions. */ + printf_unlocked (""); + __builtin_printf_unlocked (""); + printf_unlocked ("%s", ""); + __builtin_printf_unlocked ("%s", ""); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/snprintf-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/snprintf-chk-lib.c new file mode 100644 index 000000000..9daf13e82 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/snprintf-chk-lib.c @@ -0,0 +1 @@ +#include "lib/chk.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/snprintf-chk.c b/gcc/testsuite/gcc.c-torture/execute/builtins/snprintf-chk.c new file mode 100644 index 000000000..b244f8925 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/snprintf-chk.c @@ -0,0 +1,220 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation. + + Ensure builtin __snprintf_chk performs correctly. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strlen(const char *); +extern void *memcpy (void *, const void *, size_t); +extern char *strcpy (char *, const char *); +extern int memcmp (const void *, const void *, size_t); +extern void *memset (void *, int, size_t); +extern int sprintf (char *, const char *, ...); +extern int snprintf (char *, size_t, const char *, ...); + +#include "chk.h" + +const char s1[] = "123"; +char p[32] = ""; +char *s2 = "defg"; +char *s3 = "FGH"; +char *s4; +size_t l1 = 1; +static char buffer[32]; +char * volatile ptr = "barf"; /* prevent constant propagation to happen when whole program assumptions are made. */ + +void +__attribute__((noinline)) +test1 (void) +{ + chk_calls = 0; + /* snprintf_disallowed = 1; */ + + memset (buffer, 'A', 32); + snprintf (buffer, 4, "foo"); + if (memcmp (buffer, "foo", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + if (snprintf (buffer, 4, "foo bar") != 7) + abort (); + if (memcmp (buffer, "foo", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + snprintf (buffer, 32, "%s", "bar"); + if (memcmp (buffer, "bar", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + if (snprintf (buffer, 21, "%s", "bar") != 3) + abort (); + if (memcmp (buffer, "bar", 4) || buffer[4] != 'A') + abort (); + + snprintf_disallowed = 0; + + memset (buffer, 'A', 32); + if (snprintf (buffer, 4, "%d%d%d", (int) l1, (int) l1 + 1, (int) l1 + 12) + != 4) + abort (); + if (memcmp (buffer, "121", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + if (snprintf (buffer, 32, "%d%d%d", (int) l1, (int) l1 + 1, (int) l1 + 12) + != 4) + abort (); + if (memcmp (buffer, "1213", 5) || buffer[5] != 'A') + abort (); + + if (chk_calls) + abort (); + + memset (buffer, 'A', 32); + snprintf (buffer, strlen (ptr) + 1, "%s", ptr); + if (memcmp (buffer, "barf", 5) || buffer[5] != 'A') + abort (); + + memset (buffer, 'A', 32); + snprintf (buffer, l1 + 31, "%d - %c", (int) l1 + 27, *ptr); + if (memcmp (buffer, "28 - b\0AAAAA", 12)) + abort (); + + if (chk_calls != 2) + abort (); + chk_calls = 0; + + memset (s4, 'A', 32); + snprintf (s4, l1 + 6, "%d - %c", (int) l1 - 17, ptr[1]); + if (memcmp (s4, "-16 - \0AAA", 10)) + abort (); + if (chk_calls) + abort (); +} + +/* Test whether compile time checking is done where it should + and so is runtime object size checking. */ +void +__attribute__((noinline)) +test2 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4]; + char buf3[20]; + int i; + + /* The following calls should do runtime checking + - length is not known, but destination is. */ + chk_calls = 0; + snprintf (a.buf1 + 2, l1, "%s", s3 + 3); + snprintf (r, l1 + 4, "%s%c", s3 + 3, s3[3]); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + snprintf (r, strlen (s2) - 2, "%c %s", s2[2], s2 + 4); + snprintf (r + 2, l1, s3 + 3); + r = buf3; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1]; + else if (i == l1) + r = &a.buf2[7]; + else if (i == l1 + 1) + r = &buf3[5]; + else if (i == l1 + 2) + r = &a.buf1[9]; + } + snprintf (r, l1, s2 + 4); + if (chk_calls != 5) + abort (); + + /* Following have known destination and known source length, + so if optimizing certainly shouldn't result in the checking + variants. */ + chk_calls = 0; + /* snprintf_disallowed = 1; */ + snprintf (a.buf1 + 2, 4, ""); + snprintf (r, 1, "a"); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + snprintf (r, 3, "%s", s1 + 1); + r = buf3; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1]; + else if (i == l1) + r = &a.buf2[7]; + else if (i == l1 + 1) + r = &buf3[5]; + else if (i == l1 + 2) + r = &a.buf1[9]; + } + snprintf (r, 1, "%s", ""); + snprintf (r, 0, "%s", ""); + snprintf_disallowed = 0; + /* Unknown destination and source, no checking. */ + snprintf (s4, l1 + 31, "%s %d", s3, 0); + if (chk_calls) + abort (); +} + +/* Test whether runtime and/or compile time checking catches + buffer overflows. */ +void +__attribute__((noinline)) +test3 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char buf3[20]; + + chk_fail_allowed = 1; + /* Runtime checks. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + snprintf (&a.buf2[9], l1 + 1, "%c%s", s2[3], s2 + 4); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + snprintf (&a.buf2[7], l1 + 30, "%s%c", s3 + strlen (s3) - 2, *s3); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + snprintf (&a.buf2[7], l1 + 3, "%d", (int) l1 + 9999); + abort (); + } + /* This should be detectable at compile time already. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + snprintf (&buf3[19], 2, "a"); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + snprintf (&buf3[17], 4, "a"); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + snprintf (&buf3[17], 4, "%s", "abc"); + abort (); + } + chk_fail_allowed = 0; +} + +void +main_test (void) +{ +#ifndef __OPTIMIZE__ + /* Object size checking is only intended for -O[s123]. */ + return; +#endif + __asm ("" : "=r" (s2) : "0" (s2)); + __asm ("" : "=r" (s3) : "0" (s3)); + __asm ("" : "=r" (l1) : "0" (l1)); + s4 = p; + test1 (); + test2 (); + test3 (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/sprintf-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/sprintf-chk-lib.c new file mode 100644 index 000000000..9daf13e82 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/sprintf-chk-lib.c @@ -0,0 +1 @@ +#include "lib/chk.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/sprintf-chk.c b/gcc/testsuite/gcc.c-torture/execute/builtins/sprintf-chk.c new file mode 100644 index 000000000..8a283626d --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/sprintf-chk.c @@ -0,0 +1,197 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation. + + Ensure builtin __sprintf_chk performs correctly. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strlen(const char *); +extern void *memcpy (void *, const void *, size_t); +extern char *strcpy (char *, const char *); +extern int memcmp (const void *, const void *, size_t); +extern void *memset (void *, int, size_t); +extern int sprintf (char *, const char *, ...); + +#include "chk.h" + +LOCAL const char s1[] = "123"; +char p[32] = ""; +char *s2 = "defg"; +char *s3 = "FGH"; +char *s4; +size_t l1 = 1; +static char buffer[32]; +char * volatile ptr = "barf"; /* prevent constant propagation to happen when whole program assumptions are made. */ + +void +__attribute__((noinline)) +test1 (void) +{ + chk_calls = 0; + sprintf_disallowed = 1; + + memset (buffer, 'A', 32); + sprintf (buffer, "foo"); + if (memcmp (buffer, "foo", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + if (sprintf (buffer, "foo") != 3) + abort (); + if (memcmp (buffer, "foo", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + sprintf (buffer, "%s", "bar"); + if (memcmp (buffer, "bar", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + if (sprintf (buffer, "%s", "bar") != 3) + abort (); + if (memcmp (buffer, "bar", 4) || buffer[4] != 'A') + abort (); + + if (chk_calls) + abort (); + sprintf_disallowed = 0; + + memset (buffer, 'A', 32); + sprintf (buffer, "%s", ptr); + if (memcmp (buffer, "barf", 5) || buffer[5] != 'A') + abort (); + + memset (buffer, 'A', 32); + sprintf (buffer, "%d - %c", (int) l1 + 27, *ptr); + if (memcmp (buffer, "28 - b\0AAAAA", 12)) + abort (); + + if (chk_calls != 2) + abort (); + chk_calls = 0; + + sprintf (s4, "%d - %c", (int) l1 - 17, ptr[1]); + if (memcmp (s4, "-16 - a", 8)) + abort (); + if (chk_calls) + abort (); +} + +/* Test whether compile time checking is done where it should + and so is runtime object size checking. */ +void +__attribute__((noinline)) +test2 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4]; + char buf3[20]; + int i; + + /* The following calls should do runtime checking + - source length is not known, but destination is. */ + chk_calls = 0; + sprintf (a.buf1 + 2, "%s", s3 + 3); + sprintf (r, "%s%c", s3 + 3, s3[3]); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + sprintf (r, "%c %s", s2[2], s2 + 4); + sprintf (r + 2, s3 + 3); + r = buf3; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1]; + else if (i == l1) + r = &a.buf2[7]; + else if (i == l1 + 1) + r = &buf3[5]; + else if (i == l1 + 2) + r = &a.buf1[9]; + } + sprintf (r, s2 + 4); + if (chk_calls != 5) + abort (); + + /* Following have known destination and known source length, + so if optimizing certainly shouldn't result in the checking + variants. */ + chk_calls = 0; + sprintf_disallowed = 1; + sprintf (a.buf1 + 2, ""); + sprintf (r, "a"); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + sprintf (r, "%s", s1 + 1); + r = buf3; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1]; + else if (i == l1) + r = &a.buf2[7]; + else if (i == l1 + 1) + r = &buf3[5]; + else if (i == l1 + 2) + r = &a.buf1[9]; + } + sprintf (r, "%s", ""); + sprintf_disallowed = 0; + /* Unknown destination and source, no checking. */ + sprintf (s4, "%s %d", s3, 0); + if (chk_calls) + abort (); +} + +/* Test whether runtime and/or compile time checking catches + buffer overflows. */ +void +__attribute__((noinline)) +test3 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char buf3[20]; + + chk_fail_allowed = 1; + /* Runtime checks. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + sprintf (&a.buf2[9], "%c%s", s2[3], s2 + 4); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + sprintf (&a.buf2[7], "%s%c", s3 + strlen (s3) - 2, *s3); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + sprintf (&a.buf2[7], "%d", (int) l1 + 9999); + abort (); + } + /* This should be detectable at compile time already. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + sprintf (&buf3[19], "a"); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + sprintf (&buf3[17], "%s", "abc"); + abort (); + } + chk_fail_allowed = 0; +} + +void +main_test (void) +{ +#ifndef __OPTIMIZE__ + /* Object size checking is only intended for -O[s123]. */ + return; +#endif + __asm ("" : "=r" (s2) : "0" (s2)); + __asm ("" : "=r" (s3) : "0" (s3)); + __asm ("" : "=r" (l1) : "0" (l1)); + s4 = p; + test1 (); + test2 (); + test3 (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/sprintf-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/sprintf-lib.c new file mode 100644 index 000000000..3a4fe34c0 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/sprintf-lib.c @@ -0,0 +1 @@ +#include "lib/sprintf.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/sprintf.c b/gcc/testsuite/gcc.c-torture/execute/builtins/sprintf.c new file mode 100644 index 000000000..b45926469 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/sprintf.c @@ -0,0 +1,71 @@ +/* Copyright (C) 2003 Free Software Foundation. + + Test sprintf optimizations don't break anything and return the + correct results. + + Written by Roger Sayle, June 22, 2003. */ + +static char buffer[32]; + +extern void abort (); +typedef __SIZE_TYPE__ size_t; +extern int sprintf(char*, const char*, ...); +extern void *memset(void*, int, size_t); +extern int memcmp(const void*, const void*, size_t); + +void test1() +{ + sprintf(buffer,"foo"); +} + +int test2() +{ + return sprintf(buffer,"foo"); +} + +void test3() +{ + sprintf(buffer,"%s","bar"); +} + +int test4() +{ + return sprintf(buffer,"%s","bar"); +} + +void test5(char *ptr) +{ + sprintf(buffer,"%s",ptr); +} + + +void +main_test (void) +{ + memset (buffer, 'A', 32); + test1 (); + if (memcmp(buffer, "foo", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + if (test2 () != 3) + abort (); + if (memcmp(buffer, "foo", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + test3 (); + if (memcmp(buffer, "bar", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + if (test4 () != 3) + abort (); + if (memcmp(buffer, "bar", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + test5 ("barf"); + if (memcmp(buffer, "barf", 5) || buffer[5] != 'A') + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/stpcpy-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/stpcpy-chk-lib.c new file mode 100644 index 000000000..9daf13e82 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/stpcpy-chk-lib.c @@ -0,0 +1 @@ +#include "lib/chk.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/stpcpy-chk.c b/gcc/testsuite/gcc.c-torture/execute/builtins/stpcpy-chk.c new file mode 100644 index 000000000..6091f1293 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/stpcpy-chk.c @@ -0,0 +1,265 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation. + + Ensure builtin __stpcpy_chk performs correctly. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strlen(const char *); +extern void *memcpy (void *, const void *, size_t); +extern char *stpcpy (char *, const char *); +extern int memcmp (const void *, const void *, size_t); + +#include "chk.h" + +LOCAL const char s1[] = "123"; +char p[32] = ""; +char *s2 = "defg"; +char *s3 = "FGH"; +char *s4; +size_t l1 = 1; + +void +__attribute__((noinline)) +test1 (void) +{ + int i = 8; + +#if defined __i386__ || defined __x86_64__ + /* The functions below might not be optimized into direct stores on all + arches. It depends on how many instructions would be generated and + what limits the architecture chooses in STORE_BY_PIECES_P. */ + stpcpy_disallowed = 1; +#endif + if (stpcpy (p, "abcde") != p + 5 || memcmp (p, "abcde", 6)) + abort (); + if (stpcpy (p + 16, "vwxyz" + 1) != p + 16 + 4 || memcmp (p + 16, "wxyz", 5)) + abort (); + if (stpcpy (p + 1, "") != p + 1 + 0 || memcmp (p, "a\0cde", 6)) + abort (); + if (stpcpy (p + 3, "fghij") != p + 3 + 5 || memcmp (p, "a\0cfghij", 9)) + abort (); + + if (stpcpy ((i++, p + 20 + 1), "23") != (p + 20 + 1 + 2) + || i != 9 || memcmp (p + 19, "z\0""23\0", 5)) + abort (); + + if (stpcpy (stpcpy (p, "ABCD"), "EFG") != p + 7 || memcmp (p, "ABCDEFG", 8)) + abort(); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_stpcpy (p, "abcde") != p + 5 || memcmp (p, "abcde", 6)) + abort (); + + /* If return value of stpcpy is ignored, it should be optimized into + strcpy call. */ + stpcpy_disallowed = 1; + stpcpy (p + 1, "abcd"); + stpcpy_disallowed = 0; + if (memcmp (p, "aabcd", 6)) + abort (); + + if (chk_calls) + abort (); + + chk_calls = 0; + strcpy_disallowed = 1; + if (stpcpy (p, s2) != p + 4 || memcmp (p, "defg\0", 6)) + abort (); + strcpy_disallowed = 0; + stpcpy_disallowed = 1; + stpcpy (p + 2, s3); + stpcpy_disallowed = 0; + if (memcmp (p, "deFGH", 6)) + abort (); + if (chk_calls != 2) + abort (); +} + +#ifndef MAX_OFFSET +#define MAX_OFFSET (sizeof (long long)) +#endif + +#ifndef MAX_COPY +#define MAX_COPY (10 * sizeof (long long)) +#endif + +#ifndef MAX_EXTRA +#define MAX_EXTRA (sizeof (long long)) +#endif + +#define MAX_LENGTH (MAX_OFFSET + MAX_COPY + 1 + MAX_EXTRA) + +/* Use a sequence length that is not divisible by two, to make it more + likely to detect when words are mixed up. */ +#define SEQUENCE_LENGTH 31 + +static union { + char buf[MAX_LENGTH]; + long long align_int; + long double align_fp; +} u1, u2; + +volatile char *vx; + +void +__attribute__((noinline)) +test2 (void) +{ + int off1, off2, len, i; + char *p, *q, c; + + for (off1 = 0; off1 < MAX_OFFSET; off1++) + for (off2 = 0; off2 < MAX_OFFSET; off2++) + for (len = 1; len < MAX_COPY; len++) + { + for (i = 0, c = 'A'; i < MAX_LENGTH; i++, c++) + { + u1.buf[i] = 'a'; + if (c >= 'A' + SEQUENCE_LENGTH) + c = 'A'; + u2.buf[i] = c; + } + u2.buf[off2 + len] = '\0'; + + p = stpcpy (u1.buf + off1, u2.buf + off2); + if (p != u1.buf + off1 + len) + abort (); + + q = u1.buf; + for (i = 0; i < off1; i++, q++) + if (*q != 'a') + abort (); + + for (i = 0, c = 'A' + off2; i < len; i++, q++, c++) + { + if (c >= 'A' + SEQUENCE_LENGTH) + c = 'A'; + if (*q != c) + abort (); + } + + if (*q++ != '\0') + abort (); + for (i = 0; i < MAX_EXTRA; i++, q++) + if (*q != 'a') + abort (); + } +} + +/* Test whether compile time checking is done where it should + and so is runtime object size checking. */ +void +__attribute__((noinline)) +test3 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4]; + char buf3[20]; + int i; + const char *l; + + /* The following calls should do runtime checking + - source length is not known, but destination is. */ + chk_calls = 0; + vx = stpcpy (a.buf1 + 2, s3 + 3); + vx = stpcpy (r, s3 + 2); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + vx = stpcpy (r, s2 + 2); + vx = stpcpy (r + 2, s3 + 3); + r = buf3; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1]; + else if (i == l1) + r = &a.buf2[7]; + else if (i == l1 + 1) + r = &buf3[5]; + else if (i == l1 + 2) + r = &a.buf1[9]; + } + vx = stpcpy (r, s2 + 4); + if (chk_calls != 5) + abort (); + + /* Following have known destination and known source length, + so if optimizing certainly shouldn't result in the checking + variants. */ + chk_calls = 0; + vx = stpcpy (a.buf1 + 2, ""); + vx = stpcpy (r, "a"); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + vx = stpcpy (r, s1 + 1); + r = buf3; + l = "abc"; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1], l = "e"; + else if (i == l1) + r = &a.buf2[7], l = "gh"; + else if (i == l1 + 1) + r = &buf3[5], l = "jkl"; + else if (i == l1 + 2) + r = &a.buf1[9], l = ""; + } + vx = stpcpy (r, ""); + /* Here, strlen (l) + 1 is known to be at most 4 and + __builtin_object_size (&buf3[16], 0) is 4, so this doesn't need + runtime checking. */ + vx = stpcpy (&buf3[16], l); + /* Unknown destination and source, no checking. */ + vx = stpcpy (s4, s3); + stpcpy (s4 + 4, s3); + if (chk_calls) + abort (); + chk_calls = 0; +} + +/* Test whether runtime and/or compile time checking catches + buffer overflows. */ +void +__attribute__((noinline)) +test4 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char buf3[20]; + + chk_fail_allowed = 1; + /* Runtime checks. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + vx = stpcpy (&a.buf2[9], s2 + 3); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + vx = stpcpy (&a.buf2[7], s3 + strlen (s3) - 3); + abort (); + } + /* This should be detectable at compile time already. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + vx = stpcpy (&buf3[19], "a"); + abort (); + } + chk_fail_allowed = 0; +} + +void +main_test (void) +{ +#ifndef __OPTIMIZE__ + /* Object size checking is only intended for -O[s123]. */ + return; +#endif + __asm ("" : "=r" (s2) : "0" (s2)); + __asm ("" : "=r" (s3) : "0" (s3)); + __asm ("" : "=r" (l1) : "0" (l1)); + test1 (); + s4 = p; + test2 (); + test3 (); + test4 (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strcat-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strcat-chk-lib.c new file mode 100644 index 000000000..9daf13e82 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strcat-chk-lib.c @@ -0,0 +1 @@ +#include "lib/chk.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strcat-chk.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strcat-chk.c new file mode 100644 index 000000000..fea3184e8 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strcat-chk.c @@ -0,0 +1,204 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation. + + Ensure builtin __strcat_chk performs correctly. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strlen(const char *); +extern void *memcpy (void *, const void *, size_t); +extern char *strcat (char *, const char *); +extern int memcmp (const void *, const void *, size_t); +extern char *strcpy (char *, const char *); +extern int strcmp (const char *, const char *); +extern void *memset (void *, int, size_t); +#define RESET_DST_WITH(FILLER) \ + do { memset (dst, 'X', sizeof (dst)); strcpy (dst, (FILLER)); } while (0) + +#include "chk.h" + +const char s1[] = "123"; +char p[32] = ""; +char *s2 = "defg"; +char *s3 = "FGH"; +char *s4; +size_t l1 = 1; +char *s5; + +void +__attribute__((noinline)) +test1 (void) +{ + const char *const x1 = "hello world"; + const char *const x2 = ""; + char dst[64], *d2; + + chk_calls = 0; + strcat_disallowed = 1; + /* Following strcat calls should be optimized out at compile time. */ + RESET_DST_WITH (x1); + if (strcat (dst, "") != dst || strcmp (dst, x1)) + abort (); + RESET_DST_WITH (x1); + if (strcat (dst, x2) != dst || strcmp (dst, x1)) + abort (); + RESET_DST_WITH (x1); d2 = dst; + if (strcat (++d2, x2) != dst+1 || d2 != dst+1 || strcmp (dst, x1)) + abort (); + RESET_DST_WITH (x1); d2 = dst; + if (strcat (++d2+5, x2) != dst+6 || d2 != dst+1 || strcmp (dst, x1)) + abort (); + RESET_DST_WITH (x1); d2 = dst; + if (strcat (++d2+5, x1+11) != dst+6 || d2 != dst+1 || strcmp (dst, x1)) + abort (); + if (chk_calls) + abort (); + strcat_disallowed = 0; + + RESET_DST_WITH (x1); + if (strcat (dst, " 1111") != dst + || memcmp (dst, "hello world 1111\0XXX", 20)) + abort (); + + RESET_DST_WITH (x1); + if (strcat (dst+5, " 2222") != dst+5 + || memcmp (dst, "hello world 2222\0XXX", 20)) + abort (); + + RESET_DST_WITH (x1); d2 = dst; + if (strcat (++d2+5, " 3333") != dst+6 || d2 != dst+1 + || memcmp (dst, "hello world 3333\0XXX", 20)) + abort (); + + RESET_DST_WITH (x1); + strcat (strcat (strcat (strcat (strcat (strcat (dst, ": this "), ""), + "is "), "a "), "test"), "."); + if (memcmp (dst, "hello world: this is a test.\0X", 30)) + abort (); + + chk_calls = 0; + strcat_disallowed = 1; + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + RESET_DST_WITH (x1); + if (__builtin_strcat (dst, "") != dst || strcmp (dst, x1)) + abort (); + if (chk_calls) + abort (); + strcat_disallowed = 0; +} + + +/* Test whether compile time checking is done where it should + and so is runtime object size checking. */ +void +__attribute__((noinline)) +test2 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4]; + char buf3[20]; + int i; + + /* The following calls should do runtime checking + - source length is not known, but destination is. */ + memset (&a, '\0', sizeof (a)); + s5 = (char *) &a; + __asm __volatile ("" : : "r" (s5) : "memory"); + chk_calls = 0; + strcat (a.buf1 + 2, s3 + 3); + strcat (r, s3 + 2); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + memset (r, '\0', 3); + __asm __volatile ("" : : "r" (r) : "memory"); + strcat (r, s2 + 2); + strcat (r + 2, s3 + 3); + r = buf3; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1]; + else if (i == l1) + r = &a.buf2[7]; + else if (i == l1 + 1) + r = &buf3[5]; + else if (i == l1 + 2) + r = &a.buf1[9]; + } + strcat (r, s2 + 4); + if (chk_calls != 5) + abort (); + + /* Following have known destination and known source length, + but we don't know the length of dest string, so runtime checking + is needed too. */ + memset (&a, '\0', sizeof (a)); + chk_calls = 0; + s5 = (char *) &a; + __asm __volatile ("" : : "r" (s5) : "memory"); + strcat (a.buf1 + 2, "a"); + strcat (r, ""); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + memset (r, '\0', 3); + __asm __volatile ("" : : "r" (r) : "memory"); + strcat (r, s1 + 1); + if (chk_calls != 2) + abort (); + chk_calls = 0; + /* Unknown destination and source, no checking. */ + strcat (s4, s3); + if (chk_calls) + abort (); + chk_calls = 0; +} + +/* Test whether runtime and/or compile time checking catches + buffer overflows. */ +void +__attribute__((noinline)) +test3 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char buf3[20]; + + memset (&a, '\0', sizeof (a)); + memset (buf3, '\0', sizeof (buf3)); + s5 = (char *) &a; + __asm __volatile ("" : : "r" (s5) : "memory"); + s5 = buf3; + __asm __volatile ("" : : "r" (s5) : "memory"); + chk_fail_allowed = 1; + /* Runtime checks. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + strcat (&a.buf2[9], s2 + 3); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + strcat (&a.buf2[7], s3 + strlen (s3) - 3); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + strcat (&buf3[19], "a"); + abort (); + } + chk_fail_allowed = 0; +} + +void +main_test (void) +{ +#ifndef __OPTIMIZE__ + /* Object size checking is only intended for -O[s123]. */ + return; +#endif + __asm ("" : "=r" (s2) : "0" (s2)); + __asm ("" : "=r" (s3) : "0" (s3)); + __asm ("" : "=r" (l1) : "0" (l1)); + s4 = p; + test1 (); + memset (p, '\0', sizeof (p)); + test2 (); + test3 (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strcat-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strcat-lib.c new file mode 100644 index 000000000..0a0bbb886 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strcat-lib.c @@ -0,0 +1 @@ +#include "lib/strcat.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strcat.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strcat.c new file mode 100644 index 000000000..0fb1ba1c4 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strcat.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2000, 2003 Free Software Foundation. + + Ensure all expected transformations of builtin strcat occur and + perform correctly. + + Written by Kaveh R. Ghazi, 11/27/2000. */ + +extern int inside_main; +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern char *strcat (char *, const char *); +extern char *strcpy (char *, const char *); +extern void *memset (void *, int, size_t); +extern int memcmp (const void *, const void *, size_t); +#define RESET_DST_WITH(FILLER) \ + do { memset (dst, 'X', sizeof (dst)); strcpy (dst, (FILLER)); } while (0) + +void main_test (void) +{ + const char *const s1 = "hello world"; + const char *const s2 = ""; + char dst[64], *d2; + + RESET_DST_WITH (s1); + if (strcat (dst, "") != dst || memcmp (dst, "hello world\0XXX", 15)) + abort(); + RESET_DST_WITH (s1); + if (strcat (dst, s2) != dst || memcmp (dst, "hello world\0XXX", 15)) + abort(); + RESET_DST_WITH (s1); d2 = dst; + if (strcat (++d2, s2) != dst+1 || d2 != dst+1 + || memcmp (dst, "hello world\0XXX", 15)) + abort(); + RESET_DST_WITH (s1); d2 = dst; + if (strcat (++d2+5, s2) != dst+6 || d2 != dst+1 + || memcmp (dst, "hello world\0XXX", 15)) + abort(); + RESET_DST_WITH (s1); d2 = dst; + if (strcat (++d2+5, s1+11) != dst+6 || d2 != dst+1 + || memcmp (dst, "hello world\0XXX", 15)) + abort(); + +#ifndef __OPTIMIZE_SIZE__ +# if !defined __i386__ && !defined __x86_64__ + /* The functions below might not be optimized into direct stores on all + arches. It depends on how many instructions would be generated and + what limits the architecture chooses in STORE_BY_PIECES_P. */ + inside_main = 0; +# endif + + RESET_DST_WITH (s1); + if (strcat (dst, " 1111") != dst + || memcmp (dst, "hello world 1111\0XXX", 20)) + abort(); + + RESET_DST_WITH (s1); + if (strcat (dst+5, " 2222") != dst+5 + || memcmp (dst, "hello world 2222\0XXX", 20)) + abort(); + + RESET_DST_WITH (s1); d2 = dst; + if (strcat (++d2+5, " 3333") != dst+6 || d2 != dst+1 + || memcmp (dst, "hello world 3333\0XXX", 20)) + abort(); + + RESET_DST_WITH (s1); + strcat (strcat (strcat (strcat (strcat (strcat (dst, ": this "), ""), + "is "), "a "), "test"), "."); + if (memcmp (dst, "hello world: this is a test.\0X", 30)) + abort(); + + /* Set inside_main again. */ + inside_main = 1; +#endif + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + RESET_DST_WITH (s1); + if (__builtin_strcat (dst, "") != dst || memcmp (dst, "hello world\0XXX", 15)) + abort(); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strchr-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strchr-lib.c new file mode 100644 index 000000000..b3f0bd237 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strchr-lib.c @@ -0,0 +1,8 @@ +#include "lib/strchr.c" +#ifdef __vxworks +/* The RTP C library uses bzero, bfill and bcopy, all of which are defined + in the same file as index. */ +#include "lib/bzero.c" +#include "lib/bfill.c" +#include "lib/memmove.c" +#endif diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strchr.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strchr.c new file mode 100644 index 000000000..08e87c63d --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strchr.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2000, 2003 Free Software Foundation. + + Ensure all expected transformations of builtin strchr and index + occur and perform correctly. + + Written by Jakub Jelinek, 11/7/2000. */ + +extern void abort (void); +extern char *strchr (const char *, int); +extern char *index (const char *, int); + +void +main_test (void) +{ + const char *const foo = "hello world"; + + if (strchr (foo, 'x')) + abort (); + if (strchr (foo, 'o') != foo + 4) + abort (); + if (strchr (foo + 5, 'o') != foo + 7) + abort (); + if (strchr (foo, '\0') != foo + 11) + abort (); + /* Test only one instance of index since the code path is the same + as that of strchr. */ + if (index ("hello", 'z') != 0) + abort (); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_strchr (foo, 'o') != foo + 4) + abort (); + if (__builtin_index (foo, 'o') != foo + 4) + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strcmp-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strcmp-lib.c new file mode 100644 index 000000000..99c421486 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strcmp-lib.c @@ -0,0 +1 @@ +#include "lib/strcmp.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strcmp.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strcmp.c new file mode 100644 index 000000000..08a7658ea --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strcmp.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2000, 2003, 2004 Free Software Foundation. + + Ensure all expected transformations of builtin strcmp + occur and perform correctly. + + Written by Jakub Jelinek, 11/7/2000. */ + +extern void abort (void); +extern int strcmp (const char *, const char *); + +int x = 7; +char *bar = "hi world"; + +void +main_test (void) +{ + const char *const foo = "hello world"; + + if (strcmp (foo, "hello") <= 0) + abort (); + if (strcmp (foo + 2, "llo") <= 0) + abort (); + if (strcmp (foo, foo) != 0) + abort (); + if (strcmp (foo, "hello world ") >= 0) + abort (); + if (strcmp (foo + 10, "dx") >= 0) + abort (); + if (strcmp (10 + foo, "dx") >= 0) + abort (); + if (strcmp (bar, "") <= 0) + abort (); + if (strcmp ("", bar) >= 0) + abort (); + if (strcmp (bar+8, "") != 0) + abort (); + if (strcmp ("", bar+8) != 0) + abort (); + if (strcmp (bar+(--x), "") <= 0 || x != 6) + abort (); + if (strcmp ("", bar+(++x)) >= 0 || x != 7) + abort (); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_strcmp (foo, "hello") <= 0) + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-2-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-2-lib.c new file mode 100644 index 000000000..b10dfcb0d --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-2-lib.c @@ -0,0 +1 @@ +#include "lib/strcpy.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-2.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-2.c new file mode 100644 index 000000000..c3cb6d0e5 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-2.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2004 Free Software Foundation. + + Ensure builtin strcpy is optimized into memcpy + even when there is more than one possible string literal + passed to it, but all string literals passed to it + have equal length. + + Written by Jakub Jelinek, 9/15/2004. */ + +extern void abort (void); +extern char *strcpy (char *, const char *); +typedef __SIZE_TYPE__ size_t; +extern void *memcpy (void *, const void *, size_t); +extern int memcmp (const void *, const void *, size_t); + +char buf[32], *p; +int i; + +char * +__attribute__((noinline)) +test (void) +{ + int j; + const char *q = "abcdefg"; + for (j = 0; j < 3; ++j) + { + if (j == i) + q = "bcdefgh"; + else if (j == i + 1) + q = "cdefghi"; + else if (j == i + 2) + q = "defghij"; + } + p = strcpy (buf, q); + return strcpy (buf + 16, q); +} + +void +main_test (void) +{ +#ifndef __OPTIMIZE_SIZE__ + /* For -Os, strcpy above is not replaced with + memcpy (buf, q, 8);, as that is larger. */ + if (test () != buf + 16 || p != buf) + abort (); +#endif +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-chk-lib.c new file mode 100644 index 000000000..9daf13e82 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-chk-lib.c @@ -0,0 +1 @@ +#include "lib/chk.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-chk.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-chk.c new file mode 100644 index 000000000..b3c1a3899 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-chk.c @@ -0,0 +1,234 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation. + + Ensure builtin __strcpy_chk performs correctly. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strlen(const char *); +extern void *memcpy (void *, const void *, size_t); +extern char *strcpy (char *, const char *); +extern int memcmp (const void *, const void *, size_t); + +#include "chk.h" + +LOCAL const char s1[] = "123"; +char p[32] = ""; +char *s2 = "defg"; +char *s3 = "FGH"; +char *s4; +size_t l1 = 1; + +void +__attribute__((noinline)) +test1 (void) +{ + chk_calls = 0; +#ifndef __OPTIMIZE_SIZE__ + strcpy_disallowed = 1; +#else + strcpy_disallowed = 0; +#endif + + if (strcpy (p, "abcde") != p || memcmp (p, "abcde", 6)) + abort (); + if (strcpy (p + 16, "vwxyz" + 1) != p + 16 || memcmp (p + 16, "wxyz", 5)) + abort (); + if (strcpy (p + 1, "") != p + 1 || memcmp (p, "a\0cde", 6)) + abort (); + if (strcpy (p + 3, "fghij") != p + 3 || memcmp (p, "a\0cfghij", 9)) + abort (); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_strcpy (p, "abcde") != p || memcmp (p, "abcde", 6)) + abort (); + + strcpy_disallowed = 0; + if (chk_calls) + abort (); +} + +#ifndef MAX_OFFSET +#define MAX_OFFSET (sizeof (long long)) +#endif + +#ifndef MAX_COPY +#define MAX_COPY (10 * sizeof (long long)) +#endif + +#ifndef MAX_EXTRA +#define MAX_EXTRA (sizeof (long long)) +#endif + +#define MAX_LENGTH (MAX_OFFSET + MAX_COPY + 1 + MAX_EXTRA) + +/* Use a sequence length that is not divisible by two, to make it more + likely to detect when words are mixed up. */ +#define SEQUENCE_LENGTH 31 + +static union { + char buf[MAX_LENGTH]; + long long align_int; + long double align_fp; +} u1, u2; + +void +__attribute__((noinline)) +test2 (void) +{ + int off1, off2, len, i; + char *p, *q, c; + + for (off1 = 0; off1 < MAX_OFFSET; off1++) + for (off2 = 0; off2 < MAX_OFFSET; off2++) + for (len = 1; len < MAX_COPY; len++) + { + for (i = 0, c = 'A'; i < MAX_LENGTH; i++, c++) + { + u1.buf[i] = 'a'; + if (c >= 'A' + SEQUENCE_LENGTH) + c = 'A'; + u2.buf[i] = c; + } + u2.buf[off2 + len] = '\0'; + + p = strcpy (u1.buf + off1, u2.buf + off2); + if (p != u1.buf + off1) + abort (); + + q = u1.buf; + for (i = 0; i < off1; i++, q++) + if (*q != 'a') + abort (); + + for (i = 0, c = 'A' + off2; i < len; i++, q++, c++) + { + if (c >= 'A' + SEQUENCE_LENGTH) + c = 'A'; + if (*q != c) + abort (); + } + + if (*q++ != '\0') + abort (); + for (i = 0; i < MAX_EXTRA; i++, q++) + if (*q != 'a') + abort (); + } +} + +/* Test whether compile time checking is done where it should + and so is runtime object size checking. */ +void +__attribute__((noinline)) +test3 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4]; + char buf3[20]; + int i; + const char *l; + + /* The following calls should do runtime checking + - source length is not known, but destination is. */ + chk_calls = 0; + strcpy (a.buf1 + 2, s3 + 3); + strcpy (r, s3 + 2); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + strcpy (r, s2 + 2); + strcpy (r + 2, s3 + 3); + r = buf3; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1]; + else if (i == l1) + r = &a.buf2[7]; + else if (i == l1 + 1) + r = &buf3[5]; + else if (i == l1 + 2) + r = &a.buf1[9]; + } + strcpy (r, s2 + 4); + if (chk_calls != 5) + abort (); + + /* Following have known destination and known source length, + so if optimizing certainly shouldn't result in the checking + variants. */ + chk_calls = 0; + strcpy (a.buf1 + 2, ""); + strcpy (r, "a"); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + strcpy (r, s1 + 1); + r = buf3; + l = "abc"; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1], l = "e"; + else if (i == l1) + r = &a.buf2[7], l = "gh"; + else if (i == l1 + 1) + r = &buf3[5], l = "jkl"; + else if (i == l1 + 2) + r = &a.buf1[9], l = ""; + } + strcpy (r, ""); + /* Here, strlen (l) + 1 is known to be at most 4 and + __builtin_object_size (&buf3[16], 0) is 4, so this doesn't need + runtime checking. */ + strcpy (&buf3[16], l); + /* Unknown destination and source, no checking. */ + strcpy (s4, s3); + if (chk_calls) + abort (); + chk_calls = 0; +} + +/* Test whether runtime and/or compile time checking catches + buffer overflows. */ +void +__attribute__((noinline)) +test4 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char buf3[20]; + + chk_fail_allowed = 1; + /* Runtime checks. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + strcpy (&a.buf2[9], s2 + 3); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + strcpy (&a.buf2[7], s3 + strlen (s3) - 3); + abort (); + } + /* This should be detectable at compile time already. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + strcpy (&buf3[19], "a"); + abort (); + } + chk_fail_allowed = 0; +} + +void +main_test (void) +{ +#ifndef __OPTIMIZE__ + /* Object size checking is only intended for -O[s123]. */ + return; +#endif + __asm ("" : "=r" (s2) : "0" (s2)); + __asm ("" : "=r" (s3) : "0" (s3)); + __asm ("" : "=r" (l1) : "0" (l1)); + test1 (); + test2 (); + s4 = p; + test3 (); + test4 (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-lib.c new file mode 100644 index 000000000..b10dfcb0d --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-lib.c @@ -0,0 +1 @@ +#include "lib/strcpy.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy.c new file mode 100644 index 000000000..0ca62b3a2 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2000 Free Software Foundation. + + Ensure builtin memcpy and strcpy perform correctly. + + Written by Jakub Jelinek, 11/24/2000. */ + +extern void abort (void); +extern char *strcpy (char *, const char *); +typedef __SIZE_TYPE__ size_t; +extern void *memcpy (void *, const void *, size_t); +extern int memcmp (const void *, const void *, size_t); + +char p[32] = ""; + +void +main_test (void) +{ + if (strcpy (p, "abcde") != p || memcmp (p, "abcde", 6)) + abort (); + if (strcpy (p + 16, "vwxyz" + 1) != p + 16 || memcmp (p + 16, "wxyz", 5)) + abort (); + if (strcpy (p + 1, "") != p + 1 || memcmp (p, "a\0cde", 6)) + abort (); + if (strcpy (p + 3, "fghij") != p + 3 || memcmp (p, "a\0cfghij", 9)) + abort (); + if (memcpy (p, "ABCDE", 6) != p || memcmp (p, "ABCDE", 6)) + abort (); + if (memcpy (p + 16, "VWX" + 1, 2) != p + 16 || memcmp (p + 16, "WXyz", 5)) + abort (); + if (memcpy (p + 1, "", 1) != p + 1 || memcmp (p, "A\0CDE", 6)) + abort (); + if (memcpy (p + 3, "FGHI", 4) != p + 3 || memcmp (p, "A\0CFGHIj", 9)) + abort (); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_strcpy (p, "abcde") != p || memcmp (p, "abcde", 6)) + abort (); + if (__builtin_memcpy (p, "ABCDE", 6) != p || memcmp (p, "ABCDE", 6)) + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strcspn-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strcspn-lib.c new file mode 100644 index 000000000..8b1cfea01 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strcspn-lib.c @@ -0,0 +1 @@ +#include "lib/strcspn.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strcspn.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strcspn.c new file mode 100644 index 000000000..be392546a --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strcspn.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2000, 2004 Free Software Foundation. + + Ensure all expected transformations of builtin strcspn occur and + perform correctly. + + Written by Kaveh R. Ghazi, 11/27/2000. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strcspn (const char *, const char *); +extern char *strcpy (char *, const char *); + +void +main_test (void) +{ + const char *const s1 = "hello world"; + char dst[64], *d2; + + if (strcspn (s1, "hello") != 0) + abort(); + if (strcspn (s1, "z") != 11) + abort(); + if (strcspn (s1+4, "z") != 7) + abort(); + if (strcspn (s1, "hello world") != 0) + abort(); + if (strcspn (s1, "") != 11) + abort(); + strcpy (dst, s1); + if (strcspn (dst, "") != 11) + abort(); + strcpy (dst, s1); d2 = dst; + if (strcspn (++d2, "") != 10 || d2 != dst+1) + abort(); + strcpy (dst, s1); d2 = dst; + if (strcspn (++d2+5, "") != 5 || d2 != dst+1) + abort(); + if (strcspn ("", s1) != 0) + abort(); + strcpy (dst, s1); + if (strcspn ("", dst) != 0) + abort(); + strcpy (dst, s1); d2 = dst; + if (strcspn ("", ++d2) != 0 || d2 != dst+1) + abort(); + strcpy (dst, s1); d2 = dst; + if (strcspn ("", ++d2+5) != 0 || d2 != dst+1) + abort(); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_strcspn (s1, "z") != 11) + abort(); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-2-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-2-lib.c new file mode 100644 index 000000000..9753c2498 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-2-lib.c @@ -0,0 +1 @@ +#include "lib/strlen.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-2.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-2.c new file mode 100644 index 000000000..e15ad6636 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-2.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2003 Free Software Foundation. + + Test strlen optimizations on conditional expressions. + + Written by Jakub Jelinek, June 23, 2003. */ + +typedef __SIZE_TYPE__ size_t; +extern size_t strlen (const char *); +extern char *strcpy (char *, const char *); +extern int memcmp (const void *, const void *, size_t); +extern void abort (void); +extern int inside_main; + +size_t g, h, i, j, k, l; + +size_t +foo (void) +{ + if (l) + abort (); + return ++l; +} + +void +main_test (void) +{ + if (strlen (i ? "foo" + 1 : j ? "bar" + 1 : "baz" + 1) != 2) + abort (); + if (strlen (g++ ? "foo" : "bar") != 3 || g != 1) + abort (); + if (strlen (h++ ? "xfoo" + 1 : "bar") != 3 || h != 1) + abort (); + if (strlen ((i++, "baz")) != 3 || i != 1) + abort (); + /* The following calls might not optimize strlen call away. */ + inside_main = 0; + if (strlen (j ? "foo" + k++ : "bar" + k++) != 3 || k != 1) + abort (); + if (strlen (foo () ? "foo" : "bar") != 3 || l != 1) + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3-lib.c new file mode 100644 index 000000000..9753c2498 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3-lib.c @@ -0,0 +1 @@ +#include "lib/strlen.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3.c new file mode 100644 index 000000000..666ca21b9 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3.c @@ -0,0 +1,70 @@ +/* Copyright (C) 2004 Free Software Foundation. + + Test strlen on const variables initialized to string literals. + + Written by Jakub Jelinek, 9/14/2004. */ + +extern void abort (void); +extern __SIZE_TYPE__ strlen (const char *); +extern char *strcpy (char *, const char *); +static const char bar[] = "Hello, World!"; +static const char baz[] = "hello, world?"; +static const char larger[20] = "short string"; +extern int inside_main; + +int l1 = 1; +int x = 6; + +void +main_test(void) +{ +#ifdef __OPTIMIZE__ + const char *foo; + int i; +#endif + + if (strlen (bar) != 13) + abort (); + + if (strlen (bar + 3) != 10) + abort (); + + if (strlen (&bar[6]) != 7) + abort (); + + if (strlen (bar + (x++ & 7)) != 7) + abort (); + if (x != 7) + abort (); + +#ifdef __OPTIMIZE__ + foo = bar; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + foo = "HELLO, WORLD!"; + else if (i == l1) + foo = bar; + else if (i == l1 + 1) + foo = "hello, world!"; + else + foo = baz; + } + if (strlen (foo) != 13) + abort (); +#endif + + if (strlen (larger) != 12) + abort (); + if (strlen (&larger[10]) != 2) + abort (); + + inside_main = 0; + /* This will result in strlen call, because larger + array is bigger than its initializer. */ + if (strlen (larger + (x++ & 7)) != 5) + abort (); + if (x != 8) + abort (); + inside_main = 1; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-lib.c new file mode 100644 index 000000000..9753c2498 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-lib.c @@ -0,0 +1 @@ +#include "lib/strlen.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strlen.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strlen.c new file mode 100644 index 000000000..0a9681770 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strlen.c @@ -0,0 +1,71 @@ +/* Copyright (C) 2000, 2001, 2003, 2004 Free Software Foundation. + + Ensure all expected transformations of builtin strlen + occur and perform correctly. + + Written by Jakub Jelinek, 11/7/2000. + + Additional tests written by Roger Sayle, 11/02/2001: + Ensure all builtin strlen comparisons against zero are optimized + and perform correctly. The multiple calls to strcpy are to prevent + the potentially "pure" strlen calls from being removed by CSE. + + Modified by Ben Elliston, 2006-10-25: + The multiple calls to strcpy that Roger mentions above are + problematic on systems where strcpy is implemented using strlen + (which this test overrides to call abort). So, rather than use + strcpy, we perform the identical operations using array indexing + and char assignments. */ + +extern void abort (void); +extern __SIZE_TYPE__ strlen (const char *); +extern char *strcpy (char *, const char *); + +int x = 6; + +void +main_test(void) +{ + const char *const foo = "hello world"; + char str[8]; + char *ptr; + + if (strlen (foo) != 11) + abort (); + if (strlen (foo + 4) != 7) + abort (); + if (strlen (foo + (x++ & 7)) != 5) + abort (); + if (x != 7) + abort (); + + ptr = str; + ptr[0] = 'n'; ptr[1] = 't'; ptr[2] = 's'; ptr[3] = '\0'; + if (strlen (ptr) == 0) + abort (); + + ptr[0] = 'n'; ptr[1] = 't'; ptr[2] = 's'; ptr[3] = '\0'; + if (strlen (ptr) < 1) + abort (); + + ptr[0] = 'n'; ptr[1] = 't'; ptr[2] = 's'; ptr[3] = '\0'; + if (strlen (ptr) <= 0) + abort (); + + ptr[0] = 'n'; ptr[1] = 't'; ptr[2] = 's'; ptr[3] = '\0'; + if (strlen (ptr+3) != 0) + abort (); + + ptr[0] = 'n'; ptr[1] = 't'; ptr[2] = 's'; ptr[3] = '\0'; + if (strlen (ptr+3) > 0) + abort (); + + ptr[0] = 'n'; ptr[1] = 't'; ptr[2] = 's'; ptr[3] = '\0'; + if (strlen (str+3) >= 1) + abort (); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_strlen (foo) != 11) + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strncat-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strncat-chk-lib.c new file mode 100644 index 000000000..9daf13e82 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strncat-chk-lib.c @@ -0,0 +1 @@ +#include "lib/chk.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strncat-chk.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strncat-chk.c new file mode 100644 index 000000000..8904df14a --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strncat-chk.c @@ -0,0 +1,229 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation. + + Ensure builtin __strncat_chk performs correctly. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strlen (const char *); +extern void *memcpy (void *, const void *, size_t); +extern char *strcat (char *, const char *); +extern char *strncat (char *, const char *, size_t); +extern int memcmp (const void *, const void *, size_t); +extern char *strcpy (char *, const char *); +extern int strcmp (const char *, const char *); +extern void *memset (void *, int, size_t); + +#include "chk.h" + +const char s1[] = "123"; +char p[32] = ""; +char *s2 = "defg"; +char *s3 = "FGH"; +char *s4; +size_t l1 = 1; +char *s5; +int x = 123; + +void +__attribute__((noinline)) +test1 (void) +{ + const char *const s1 = "hello world"; + const char *const s2 = ""; + const char *s3; + char dst[64], *d2; + + /* Following strncat calls should be all optimized out. */ + chk_calls = 0; + strncat_disallowed = 1; + strcat_disallowed = 1; + strcpy (dst, s1); + if (strncat (dst, "", 100) != dst || strcmp (dst, s1)) + abort (); + strcpy (dst, s1); + if (strncat (dst, s2, 100) != dst || strcmp (dst, s1)) + abort (); + strcpy (dst, s1); d2 = dst; + if (strncat (++d2, s2, 100) != dst+1 || d2 != dst+1 || strcmp (dst, s1)) + abort (); + strcpy (dst, s1); d2 = dst; + if (strncat (++d2+5, s2, 100) != dst+6 || d2 != dst+1 || strcmp (dst, s1)) + abort (); + strcpy (dst, s1); d2 = dst; + if (strncat (++d2+5, s1+11, 100) != dst+6 || d2 != dst+1 || strcmp (dst, s1)) + abort (); + strcpy (dst, s1); d2 = dst; + if (strncat (++d2+5, s1, 0) != dst+6 || d2 != dst+1 || strcmp (dst, s1)) + abort (); + strcpy (dst, s1); d2 = dst; s3 = s1; + if (strncat (++d2+5, ++s3, 0) != dst+6 || d2 != dst+1 || strcmp (dst, s1) + || s3 != s1 + 1) + abort (); + strcpy (dst, s1); d2 = dst; + if (strncat (++d2+5, "", ++x) != dst+6 || d2 != dst+1 || x != 124 + || strcmp (dst, s1)) + abort (); + if (chk_calls) + abort (); + strcat_disallowed = 0; + + /* These __strncat_chk calls should be optimized into __strcat_chk, + as strlen (src) <= len. */ + strcpy (dst, s1); + if (strncat (dst, "foo", 3) != dst || strcmp (dst, "hello worldfoo")) + abort (); + strcpy (dst, s1); + if (strncat (dst, "foo", 100) != dst || strcmp (dst, "hello worldfoo")) + abort (); + strcpy (dst, s1); + if (strncat (dst, s1, 100) != dst || strcmp (dst, "hello worldhello world")) + abort (); + if (chk_calls != 3) + abort (); + + chk_calls = 0; + /* The following calls have side-effects in dest, so are not checked. */ + strcpy (dst, s1); d2 = dst; + if (__builtin___strncat_chk (++d2, s1, 100, os (++d2)) != dst+1 + || d2 != dst+1 || strcmp (dst, "hello worldhello world")) + abort (); + strcpy (dst, s1); d2 = dst; + if (__builtin___strncat_chk (++d2+5, s1, 100, os (++d2+5)) != dst+6 + || d2 != dst+1 || strcmp (dst, "hello worldhello world")) + abort (); + strcpy (dst, s1); d2 = dst; + if (__builtin___strncat_chk (++d2+5, s1+5, 100, os (++d2+5)) != dst+6 + || d2 != dst+1 || strcmp (dst, "hello world world")) + abort (); + if (chk_calls) + abort (); + + chk_calls = 0; + strcat_disallowed = 1; + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + strcpy (dst, s1); + if (__builtin_strncat (dst, "", 100) != dst || strcmp (dst, s1)) + abort (); + + if (chk_calls) + abort (); + strncat_disallowed = 0; + strcat_disallowed = 0; +} + +/* Test whether compile time checking is done where it should + and so is runtime object size checking. */ +void +__attribute__((noinline)) +test2 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4]; + char buf3[20]; + int i; + + /* The following calls should do runtime checking. */ + memset (&a, '\0', sizeof (a)); + s5 = (char *) &a; + __asm __volatile ("" : : "r" (s5) : "memory"); + chk_calls = 0; + strncat (a.buf1 + 2, s3 + 3, l1 - 1); + strncat (r, s3 + 2, l1); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + memset (r, '\0', 3); + __asm __volatile ("" : : "r" (r) : "memory"); + strncat (r, s2 + 2, l1 + 1); + strncat (r + 2, s3 + 3, l1 - 1); + r = buf3; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1]; + else if (i == l1) + r = &a.buf2[7]; + else if (i == l1 + 1) + r = &buf3[5]; + else if (i == l1 + 2) + r = &a.buf1[9]; + } + strncat (r, s2 + 4, l1); + if (chk_calls != 5) + abort (); + + /* Following have known destination and known source length, + but we don't know the length of dest string, so runtime checking + is needed too. */ + memset (&a, '\0', sizeof (a)); + chk_calls = 0; + s5 = (char *) &a; + __asm __volatile ("" : : "r" (s5) : "memory"); + strncat (a.buf1 + 2, "a", 5); + strncat (r, "def", 0); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + memset (r, '\0', 3); + __asm __volatile ("" : : "r" (r) : "memory"); + strncat (r, s1 + 1, 2); + if (chk_calls != 2) + abort (); + chk_calls = 0; + strcat_disallowed = 1; + /* Unknown destination and source, no checking. */ + strncat (s4, s3, l1 + 1); + strcat_disallowed = 0; + if (chk_calls) + abort (); +} + +/* Test whether runtime and/or compile time checking catches + buffer overflows. */ +void +__attribute__((noinline)) +test3 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char buf3[20]; + + memset (&a, '\0', sizeof (a)); + memset (buf3, '\0', sizeof (buf3)); + s5 = (char *) &a; + __asm __volatile ("" : : "r" (s5) : "memory"); + s5 = buf3; + __asm __volatile ("" : : "r" (s5) : "memory"); + chk_fail_allowed = 1; + /* Runtime checks. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + strncat (&a.buf2[9], s2 + 3, 4); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + strncat (&a.buf2[7], s3 + strlen (s3) - 3, 3); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + strncat (&buf3[19], "abcde", 1); + abort (); + } + chk_fail_allowed = 0; +} + +void +main_test (void) +{ +#ifndef __OPTIMIZE__ + /* Object size checking is only intended for -O[s123]. */ + return; +#endif + __asm ("" : "=r" (s2) : "0" (s2)); + __asm ("" : "=r" (s3) : "0" (s3)); + __asm ("" : "=r" (l1) : "0" (l1)); + s4 = p; + test1 (); + memset (p, '\0', sizeof (p)); + test2 (); + test3 (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strncat-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strncat-lib.c new file mode 100644 index 000000000..1405a48f4 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strncat-lib.c @@ -0,0 +1 @@ +#include "lib/strncat.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strncat.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strncat.c new file mode 100644 index 000000000..1a093baf7 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strncat.c @@ -0,0 +1,82 @@ +/* Copyright (C) 2000, 2003 Free Software Foundation. + + Ensure all expected transformations of builtin strncat occur and + perform correctly. + + Written by Kaveh R. Ghazi, 11/27/2000. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern char *strncat (char *, const char *, size_t); +extern char *strcpy (char *, const char *); +extern void *memset (void *, int, size_t); +extern int memcmp (const void *, const void *, size_t); +int x = 123; + +/* Reset the destination buffer to a known state. */ +#define RESET_DST_WITH(FILLER) \ + do { memset (dst, 'X', sizeof (dst)); strcpy (dst, (FILLER)); } while (0) + +void +main_test (void) +{ + const char *const s1 = "hello world"; + const char *const s2 = ""; + char dst[64], *d2; + + RESET_DST_WITH (s1); + if (strncat (dst, "", 100) != dst || memcmp (dst, "hello world\0XXX", 15)) + abort(); + RESET_DST_WITH (s1); + if (strncat (dst, s2, 100) != dst || memcmp (dst, "hello world\0XXX", 15)) + abort(); + RESET_DST_WITH (s1); d2 = dst; + if (strncat (++d2, s2, 100) != dst+1 || d2 != dst+1 + || memcmp (dst, "hello world\0XXX", 15)) + abort(); + RESET_DST_WITH (s1); d2 = dst; + if (strncat (++d2+5, s2, 100) != dst+6 || d2 != dst+1 + || memcmp (dst, "hello world\0XXX", 15)) + abort(); + RESET_DST_WITH (s1); d2 = dst; + if (strncat (++d2+5, s1+11, 100) != dst+6 || d2 != dst+1 + || memcmp (dst, "hello world\0XXX", 15)) + abort(); + RESET_DST_WITH (s1); d2 = dst; + if (strncat (++d2+5, s1, 0) != dst+6 || d2 != dst+1 + || memcmp (dst, "hello world\0XXX", 15)) + abort(); + RESET_DST_WITH (s1); d2 = dst; + if (strncat (++d2+5, "", ++x) != dst+6 || d2 != dst+1 || x != 124 + || memcmp (dst, "hello world\0XXX", 15)) + abort(); + + RESET_DST_WITH (s1); + if (strncat (dst, "foo", 3) != dst || memcmp (dst, "hello worldfoo\0XXX", 18)) + abort(); + RESET_DST_WITH (s1); + if (strncat (dst, "foo", 100) != dst || memcmp (dst, "hello worldfoo\0XXX", 18)) + abort(); + RESET_DST_WITH (s1); + if (strncat (dst, s1, 100) != dst || memcmp (dst, "hello worldhello world\0XXX", 26)) + abort(); + RESET_DST_WITH (s1); d2 = dst; + if (strncat (++d2, s1, 100) != dst+1 || d2 != dst+1 + || memcmp (dst, "hello worldhello world\0XXX", 26)) + abort(); + RESET_DST_WITH (s1); d2 = dst; + if (strncat (++d2+5, s1, 100) != dst+6 || d2 != dst+1 + || memcmp (dst, "hello worldhello world\0XXX", 26)) + abort(); + RESET_DST_WITH (s1); d2 = dst; + if (strncat (++d2+5, s1+5, 100) != dst+6 || d2 != dst+1 + || memcmp (dst, "hello world world\0XXX", 21)) + abort(); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + RESET_DST_WITH (s1); + if (__builtin_strncat (dst, "", 100) != dst + || memcmp (dst, "hello world\0XXX", 15)) + abort(); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strncmp-2-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strncmp-2-lib.c new file mode 100644 index 000000000..266c4a49b --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strncmp-2-lib.c @@ -0,0 +1 @@ +#include "lib/strncmp.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strncmp-2.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strncmp-2.c new file mode 100644 index 000000000..fe3462724 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strncmp-2.c @@ -0,0 +1,173 @@ +/* Copyright (C) 2000, 2001, 2003, 2005 Free Software Foundation. + + Ensure all expected transformations of builtin strncmp occur and + perform correctly. + + Written by Kaveh R. Ghazi, 11/26/2000. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern int strncmp (const char *, const char *, size_t); + +void +main_test (void) +{ +#if !defined(__OPTIMIZE__) || ((defined(__i386__) || defined (__x86_64__)) && !defined(__OPTIMIZE_SIZE__)) + /* These tests work on platforms which support cmpstrsi. We test it + at -O0 on all platforms to ensure the strncmp logic is correct. */ + const char *const s1 = "hello world"; + const char *s2; + int n = 6, x; + + s2 = s1; + if (strncmp (++s2, "ello", 3) != 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp ("ello", ++s2, 3) != 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp (++s2, "ello", 4) != 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp ("ello", ++s2, 4) != 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp (++s2, "ello", 5) <= 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp ("ello", ++s2, 5) >= 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp (++s2, "ello", 6) <= 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp ("ello", ++s2, 6) >= 0 || s2 != s1+1) + abort(); + + s2 = s1; + if (strncmp (++s2, "zllo", 3) >= 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp ("zllo", ++s2, 3) <= 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp (++s2, "zllo", 4) >= 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp ("zllo", ++s2, 4) <= 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp (++s2, "zllo", 5) >= 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp ("zllo", ++s2, 5) <= 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp (++s2, "zllo", 6) >= 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp ("zllo", ++s2, 6) <= 0 || s2 != s1+1) + abort(); + + s2 = s1; + if (strncmp (++s2, "allo", 3) <= 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp ("allo", ++s2, 3) >= 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp (++s2, "allo", 4) <= 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp ("allo", ++s2, 4) >= 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp (++s2, "allo", 5) <= 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp ("allo", ++s2, 5) >= 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp (++s2, "allo", 6) <= 0 || s2 != s1+1) + abort(); + s2 = s1; + if (strncmp ("allo", ++s2, 6) >= 0 || s2 != s1+1) + abort(); + + s2 = s1; n = 2; x = 1; + if (strncmp (++s2, s1+(x&3), ++n) != 0 || s2 != s1+1 || n != 3) + abort(); + s2 = s1; n = 2; x = 1; + if (strncmp (s1+(x&3), ++s2, ++n) != 0 || s2 != s1+1 || n != 3) + abort(); + s2 = s1; n = 3; x = 1; + if (strncmp (++s2, s1+(x&3), ++n) != 0 || s2 != s1+1 || n != 4) + abort(); + s2 = s1; n = 3; x = 1; + if (strncmp (s1+(x&3), ++s2, ++n) != 0 || s2 != s1+1 || n != 4) + abort(); + s2 = s1; n = 4; x = 1; + if (strncmp (++s2, s1+(x&3), ++n) != 0 || s2 != s1+1 || n != 5) + abort(); + s2 = s1; n = 4; x = 1; + if (strncmp (s1+(x&3), ++s2, ++n) != 0 || s2 != s1+1 || n != 5) + abort(); + s2 = s1; n = 5; x = 1; + if (strncmp (++s2, s1+(x&3), ++n) != 0 || s2 != s1+1 || n != 6) + abort(); + s2 = s1; n = 5; x = 1; + if (strncmp (s1+(x&3), ++s2, ++n) != 0 || s2 != s1+1 || n != 6) + abort(); + + s2 = s1; n = 2; + if (strncmp (++s2, "zllo", ++n) >= 0 || s2 != s1+1 || n != 3) + abort(); + s2 = s1; n = 2; x = 1; + if (strncmp ("zllo", ++s2, ++n) <= 0 || s2 != s1+1 || n != 3) + abort(); + s2 = s1; n = 3; x = 1; + if (strncmp (++s2, "zllo", ++n) >= 0 || s2 != s1+1 || n != 4) + abort(); + s2 = s1; n = 3; x = 1; + if (strncmp ("zllo", ++s2, ++n) <= 0 || s2 != s1+1 || n != 4) + abort(); + s2 = s1; n = 4; x = 1; + if (strncmp (++s2, "zllo", ++n) >= 0 || s2 != s1+1 || n != 5) + abort(); + s2 = s1; n = 4; x = 1; + if (strncmp ("zllo", ++s2, ++n) <= 0 || s2 != s1+1 || n != 5) + abort(); + s2 = s1; n = 5; x = 1; + if (strncmp (++s2, "zllo", ++n) >= 0 || s2 != s1+1 || n != 6) + abort(); + s2 = s1; n = 5; x = 1; + if (strncmp ("zllo", ++s2, ++n) <= 0 || s2 != s1+1 || n != 6) + abort(); + + s2 = s1; n = 2; + if (strncmp (++s2, "allo", ++n) <= 0 || s2 != s1+1 || n != 3) + abort(); + s2 = s1; n = 2; x = 1; + if (strncmp ("allo", ++s2, ++n) >= 0 || s2 != s1+1 || n != 3) + abort(); + s2 = s1; n = 3; x = 1; + if (strncmp (++s2, "allo", ++n) <= 0 || s2 != s1+1 || n != 4) + abort(); + s2 = s1; n = 3; x = 1; + if (strncmp ("allo", ++s2, ++n) >= 0 || s2 != s1+1 || n != 4) + abort(); + s2 = s1; n = 4; x = 1; + if (strncmp (++s2, "allo", ++n) <= 0 || s2 != s1+1 || n != 5) + abort(); + s2 = s1; n = 4; x = 1; + if (strncmp ("allo", ++s2, ++n) >= 0 || s2 != s1+1 || n != 5) + abort(); + s2 = s1; n = 5; x = 1; + if (strncmp (++s2, "allo", ++n) <= 0 || s2 != s1+1 || n != 6) + abort(); + s2 = s1; n = 5; x = 1; + if (strncmp ("allo", ++s2, ++n) >= 0 || s2 != s1+1 || n != 6) + abort(); + +#endif +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strncmp-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strncmp-lib.c new file mode 100644 index 000000000..266c4a49b --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strncmp-lib.c @@ -0,0 +1 @@ +#include "lib/strncmp.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strncmp.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strncmp.c new file mode 100644 index 000000000..2c22b7d01 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strncmp.c @@ -0,0 +1,73 @@ +/* Copyright (C) 2000, 2001, 2003 Free Software Foundation. + + Ensure all expected transformations of builtin strncmp occur and + perform correctly. + + Written by Kaveh R. Ghazi, 11/26/2000. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern int strncmp (const char *, const char *, size_t); + +void +main_test (void) +{ + const char *const s1 = "hello world"; + const char *s2, *s3; + + if (strncmp (s1, "hello world", 12) != 0) + abort(); + if (strncmp ("hello world", s1, 12) != 0) + abort(); + if (strncmp ("hello", "hello", 6) != 0) + abort(); + if (strncmp ("hello", "hello", 2) != 0) + abort(); + if (strncmp ("hello", "hello", 100) != 0) + abort(); + if (strncmp (s1+10, "d", 100) != 0) + abort(); + if (strncmp (10+s1, "d", 100) != 0) + abort(); + if (strncmp ("d", s1+10, 1) != 0) + abort(); + if (strncmp ("d", 10+s1, 1) != 0) + abort(); + if (strncmp ("hello", "aaaaa", 100) <= 0) + abort(); + if (strncmp ("aaaaa", "hello", 100) >= 0) + abort(); + if (strncmp ("hello", "aaaaa", 1) <= 0) + abort(); + if (strncmp ("aaaaa", "hello", 1) >= 0) + abort(); + + s2 = s1; s3 = s1+4; + if (strncmp (++s2, ++s3, 0) != 0 || s2 != s1+1 || s3 != s1+5) + abort(); + s2 = s1; + if (strncmp (++s2, "", 1) <= 0 || s2 != s1+1) + abort(); + if (strncmp ("", ++s2, 1) >= 0 || s2 != s1+2) + abort(); + if (strncmp (++s2, "", 100) <= 0 || s2 != s1+3) + abort(); + if (strncmp ("", ++s2, 100) >= 0 || s2 != s1+4) + abort(); + if (strncmp (++s2+6, "", 100) != 0 || s2 != s1+5) + abort(); + if (strncmp ("", ++s2+5, 100) != 0 || s2 != s1+6) + abort(); + if (strncmp ("ozz", ++s2, 1) != 0 || s2 != s1+7) + abort(); + if (strncmp (++s2, "rzz", 1) != 0 || s2 != s1+8) + abort(); + s2 = s1; s3 = s1+4; + if (strncmp (++s2, ++s3+2, 1) >= 0 || s2 != s1+1 || s3 != s1+5) + abort(); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_strncmp ("hello", "a", 100) <= 0) + abort(); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strncpy-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strncpy-chk-lib.c new file mode 100644 index 000000000..9daf13e82 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strncpy-chk-lib.c @@ -0,0 +1 @@ +#include "lib/chk.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strncpy-chk.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strncpy-chk.c new file mode 100644 index 000000000..9e10dba1b --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strncpy-chk.c @@ -0,0 +1,227 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation. + + Ensure builtin __strncpy_chk performs correctly. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strlen(const char *); +extern void *memcpy (void *, const void *, size_t); +extern char *strncpy (char *, const char *, size_t); +extern int memcmp (const void *, const void *, size_t); +extern int strcmp (const char *, const char *); +extern int strncmp (const char *, const char *, size_t); +extern void *memset (void *, int, size_t); + +#include "chk.h" + +const char s1[] = "123"; +char p[32] = ""; +char * volatile s2 = "defg"; /* prevent constant propagation to happen when whole program assumptions are made. */ +char * volatile s3 = "FGH"; /* prevent constant propagation to happen when whole program assumptions are made. */ +char *s4; +volatile size_t l1 = 1; /* prevent constant propagation to happen when whole program assumptions are made. */ +int i; + +void +__attribute__((noinline)) +test1 (void) +{ + const char *const src = "hello world"; + const char *src2; + char dst[64], *dst2; + + strncpy_disallowed = 1; + chk_calls = 0; + + memset (dst, 0, sizeof (dst)); + if (strncpy (dst, src, 4) != dst || strncmp (dst, src, 4)) + abort(); + + memset (dst, 0, sizeof (dst)); + if (strncpy (dst+16, src, 4) != dst+16 || strncmp (dst+16, src, 4)) + abort(); + + memset (dst, 0, sizeof (dst)); + if (strncpy (dst+32, src+5, 4) != dst+32 || strncmp (dst+32, src+5, 4)) + abort(); + + memset (dst, 0, sizeof (dst)); + dst2 = dst; + if (strncpy (++dst2, src+5, 4) != dst+1 || strncmp (dst2, src+5, 4) + || dst2 != dst+1) + abort(); + + memset (dst, 0, sizeof (dst)); + if (strncpy (dst, src, 0) != dst || strcmp (dst, "")) + abort(); + + memset (dst, 0, sizeof (dst)); + dst2 = dst; src2 = src; + if (strncpy (++dst2, ++src2, 0) != dst+1 || strcmp (dst2, "") + || dst2 != dst+1 || src2 != src+1) + abort(); + + memset (dst, 0, sizeof (dst)); + dst2 = dst; src2 = src; + if (strncpy (++dst2+5, ++src2+5, 0) != dst+6 || strcmp (dst2+5, "") + || dst2 != dst+1 || src2 != src+1) + abort(); + + memset (dst, 0, sizeof (dst)); + if (strncpy (dst, src, 12) != dst || strcmp (dst, src)) + abort(); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + memset (dst, 0, sizeof (dst)); + if (__builtin_strncpy (dst, src, 4) != dst || strncmp (dst, src, 4)) + abort(); + + memset (dst, 0, sizeof (dst)); + if (strncpy (dst, i++ ? "xfoo" + 1 : "bar", 4) != dst + || strcmp (dst, "bar") + || i != 1) + abort (); + + if (chk_calls) + abort (); + strncpy_disallowed = 0; +} + +void +__attribute__((noinline)) +test2 (void) +{ + chk_calls = 0; + /* No runtime checking should be done here, both destination + and length are unknown. */ + strncpy (s4, "abcd", l1 + 1); + if (chk_calls) + abort (); +} + +/* Test whether compile time checking is done where it should + and so is runtime object size checking. */ +void +__attribute__((noinline)) +test3 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4]; + char buf3[20]; + int i; + const char *l; + size_t l2; + + /* The following calls should do runtime checking + - source length is not known, but destination is. */ + chk_calls = 0; + strncpy (a.buf1 + 2, s3 + 3, l1); + strncpy (r, s3 + 2, l1 + 2); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + strncpy (r, s2 + 2, l1 + 2); + strncpy (r + 2, s3 + 3, l1); + r = buf3; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1]; + else if (i == l1) + r = &a.buf2[7]; + else if (i == l1 + 1) + r = &buf3[5]; + else if (i == l1 + 2) + r = &a.buf1[9]; + } + strncpy (r, s2 + 4, l1); + if (chk_calls != 5) + abort (); + + /* Following have known destination and known length, + so if optimizing certainly shouldn't result in the checking + variants. */ + chk_calls = 0; + strncpy (a.buf1 + 2, "", 3); + strncpy (a.buf1 + 2, "", 0); + strncpy (r, "a", 1); + strncpy (r, "a", 3); + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + strncpy (r, s1 + 1, 3); + strncpy (r, s1 + 1, 2); + r = buf3; + l = "abc"; + l2 = 4; + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + r = &a.buf1[1], l = "e", l2 = 2; + else if (i == l1) + r = &a.buf2[7], l = "gh", l2 = 3; + else if (i == l1 + 1) + r = &buf3[5], l = "jkl", l2 = 4; + else if (i == l1 + 2) + r = &a.buf1[9], l = "", l2 = 1; + } + strncpy (r, "", 1); + /* Here, strlen (l) + 1 is known to be at most 4 and + __builtin_object_size (&buf3[16], 0) is 4, so this doesn't need + runtime checking. */ + strncpy (&buf3[16], l, l2); + strncpy (&buf3[15], "abc", l2); + strncpy (&buf3[10], "fghij", l2); + if (chk_calls) + abort (); + chk_calls = 0; +} + +/* Test whether runtime and/or compile time checking catches + buffer overflows. */ +void +__attribute__((noinline)) +test4 (void) +{ + struct A { char buf1[10]; char buf2[10]; } a; + char buf3[20]; + + chk_fail_allowed = 1; + /* Runtime checks. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + strncpy (&a.buf2[9], s2 + 4, l1 + 1); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + strncpy (&a.buf2[7], s3, l1 + 4); + abort (); + } + /* This should be detectable at compile time already. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + strncpy (&buf3[19], "abc", 2); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + strncpy (&buf3[18], "", 3); + abort (); + } + chk_fail_allowed = 0; +} + +void +main_test (void) +{ +#ifndef __OPTIMIZE__ + /* Object size checking is only intended for -O[s123]. */ + return; +#endif + __asm ("" : "=r" (s2) : "0" (s2)); + __asm ("" : "=r" (s3) : "0" (s3)); + __asm ("" : "=r" (l1) : "0" (l1)); + test1 (); + s4 = p; + test2 (); + test3 (); + test4 (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strncpy-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strncpy-lib.c new file mode 100644 index 000000000..784f72d03 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strncpy-lib.c @@ -0,0 +1 @@ +#include "lib/strncpy.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strncpy.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strncpy.c new file mode 100644 index 000000000..9918cdf6a --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strncpy.c @@ -0,0 +1,75 @@ +/* Copyright (C) 2000, 2005 Free Software Foundation. + + Ensure all expected transformations of builtin strncpy occur and + perform correctly. + + Written by Kaveh R. Ghazi, 11/25/2000. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern char *strncpy (char *, const char *, size_t); +extern int memcmp (const void *, const void *, size_t); +extern void *memset (void *, int, size_t); + +/* Reset the destination buffer to a known state. */ +#define RESET_DST memset(dst, 'X', sizeof(dst)) + +int i; + +void +main_test (void) +{ + const char *const src = "hello world"; + const char *src2; + char dst[64], *dst2; + + RESET_DST; + if (strncpy (dst, src, 4) != dst || memcmp (dst, "hellXXX", 7)) + abort(); + + RESET_DST; + if (strncpy (dst+16, src, 4) != dst+16 || memcmp (dst+16, "hellXXX", 7)) + abort(); + + RESET_DST; + if (strncpy (dst+32, src+5, 4) != dst+32 || memcmp (dst+32, " worXXX", 7)) + abort(); + + RESET_DST; + dst2 = dst; + if (strncpy (++dst2, src+5, 4) != dst+1 || memcmp (dst2, " worXXX", 7) + || dst2 != dst+1) + abort(); + + RESET_DST; + if (strncpy (dst, src, 0) != dst || memcmp (dst, "XXX", 3)) + abort(); + + RESET_DST; + dst2 = dst; src2 = src; + if (strncpy (++dst2, ++src2, 0) != dst+1 || memcmp (dst2, "XXX", 3) + || dst2 != dst+1 || src2 != src+1) + abort(); + + RESET_DST; + dst2 = dst; src2 = src; + if (strncpy (++dst2+5, ++src2+5, 0) != dst+6 || memcmp (dst2+5, "XXX", 3) + || dst2 != dst+1 || src2 != src+1) + abort(); + + RESET_DST; + if (strncpy (dst, src, 12) != dst || memcmp (dst, "hello world\0XXX", 15)) + abort(); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + RESET_DST; + if (__builtin_strncpy (dst, src, 4) != dst || memcmp (dst, "hellXXX", 7)) + abort(); + + RESET_DST; + if (strncpy (dst, i++ ? "xfoo" + 1 : "bar", 4) != dst + || memcmp (dst, "bar\0XXX", 7) + || i != 1) + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strpbrk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strpbrk-lib.c new file mode 100644 index 000000000..66bf8be7c --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strpbrk-lib.c @@ -0,0 +1 @@ +#include "lib/strpbrk.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strpbrk.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strpbrk.c new file mode 100644 index 000000000..cc963a9af --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strpbrk.c @@ -0,0 +1,42 @@ +/* Copyright (C) 2000 Free Software Foundation. + + Ensure all expected transformations of builtin strpbrk occur and + perform correctly. + + Written by Kaveh R. Ghazi, 11/6/2000. */ + +extern void abort(void); +extern char *strpbrk (const char *, const char *); +extern int strcmp (const char *, const char *); + +void fn (const char *foo, const char *const *bar) +{ + if (strcmp(strpbrk ("hello world", "lrooo"), "llo world") != 0) + abort(); + if (strpbrk (foo, "") != 0) + abort(); + if (strpbrk (foo + 4, "") != 0) + abort(); + if (strpbrk (*bar--, "") != 0) + abort(); + if (strpbrk (*bar, "h") != foo) + abort(); + if (strpbrk (foo, "h") != foo) + abort(); + if (strpbrk (foo, "w") != foo + 6) + abort(); + if (strpbrk (foo + 6, "o") != foo + 7) + abort(); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_strpbrk (foo + 6, "o") != foo + 7) + abort(); +} + +void +main_test (void) +{ + const char *const foo[] = { "hello world", "bye bye world" }; + fn (foo[0], foo + 1); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strpcpy-2-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strpcpy-2-lib.c new file mode 100644 index 000000000..b31cdf4f5 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strpcpy-2-lib.c @@ -0,0 +1 @@ +#include "lib/stpcpy.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strpcpy-2.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strpcpy-2.c new file mode 100644 index 000000000..eb275c422 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strpcpy-2.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2003 Free Software Foundation. + + Ensure that builtin stpcpy performs correctly. + + Written by Jakub Jelinek, 21/05/2003. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern int memcmp (const void *, const void *, size_t); +extern char *stpcpy (char *, const char *); +extern int inside_main; + +long buf1[64]; +char *buf2 = (char *) (buf1 + 32); +long buf5[20]; +char buf7[20]; + +void +__attribute__((noinline)) +test (long *buf3, char *buf4, char *buf6, int n) +{ + int i = 4; + + if (stpcpy ((char *) buf3, "abcdefghijklmnop") != (char *) buf1 + 16 + || memcmp (buf1, "abcdefghijklmnop", 17)) + abort (); + + if (__builtin_stpcpy ((char *) buf3, "ABCDEFG") != (char *) buf1 + 7 + || memcmp (buf1, "ABCDEFG\0ijklmnop", 17)) + abort (); + + if (stpcpy ((char *) buf3 + i++, "x") != (char *) buf1 + 5 + || memcmp (buf1, "ABCDx\0G\0ijklmnop", 17)) + abort (); +} + +void +main_test (void) +{ + /* All these tests are allowed to call mempcpy/stpcpy. */ + inside_main = 0; + __builtin_memcpy (buf5, "RSTUVWXYZ0123456789", 20); + __builtin_memcpy (buf7, "RSTUVWXYZ0123456789", 20); + test (buf1, buf2, "rstuvwxyz", 0); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strpcpy-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strpcpy-lib.c new file mode 100644 index 000000000..b31cdf4f5 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strpcpy-lib.c @@ -0,0 +1 @@ +#include "lib/stpcpy.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strpcpy.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strpcpy.c new file mode 100644 index 000000000..737bfaa80 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strpcpy.c @@ -0,0 +1,60 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation. + + Ensure builtin stpcpy performs correctly. + + Written by Kaveh Ghazi, 4/11/2003. */ + +typedef __SIZE_TYPE__ size_t; + +extern void abort (void); +extern char *strcpy (char *, const char *); +extern char *stpcpy (char *, const char *); +extern int memcmp (const void *, const void *, size_t); + +extern int inside_main; + +const char s1[] = "123"; +char p[32] = ""; +char *s2 = "defg"; +char *s3 = "FGH"; +size_t l1 = 1; + +void +main_test (void) +{ + int i = 8; + +#if !defined __i386__ && !defined __x86_64__ + /* The functions below might not be optimized into direct stores on all + arches. It depends on how many instructions would be generated and + what limits the architecture chooses in STORE_BY_PIECES_P. */ + inside_main = 0; +#endif + if (stpcpy (p, "abcde") != p + 5 || memcmp (p, "abcde", 6)) + abort (); + if (stpcpy (p + 16, "vwxyz" + 1) != p + 16 + 4 || memcmp (p + 16, "wxyz", 5)) + abort (); + if (stpcpy (p + 1, "") != p + 1 + 0 || memcmp (p, "a\0cde", 6)) + abort (); + if (stpcpy (p + 3, "fghij") != p + 3 + 5 || memcmp (p, "a\0cfghij", 9)) + abort (); + + if (stpcpy ((i++, p + 20 + 1), "23") != (p + 20 + 1 + 2) + || i != 9 || memcmp (p + 19, "z\0""23\0", 5)) + abort (); + + if (stpcpy (stpcpy (p, "ABCD"), "EFG") != p + 7 || memcmp (p, "ABCDEFG", 8)) + abort(); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_stpcpy (p, "abcde") != p + 5 || memcmp (p, "abcde", 6)) + abort (); + + /* If the result of stpcpy is ignored, gcc should use strcpy. + This should be optimized always, so set inside_main again. */ + inside_main = 1; + stpcpy (p + 3, s3); + if (memcmp (p, "abcFGH", 6)) + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strrchr-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strrchr-lib.c new file mode 100644 index 000000000..9194c555f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strrchr-lib.c @@ -0,0 +1,8 @@ +#include "lib/strrchr.c" +#ifdef __vxworks +/* The RTP C library uses bzero, bfill and bcopy, all of which are defined + in the same file as rindex. */ +#include "lib/bzero.c" +#include "lib/bfill.c" +#include "lib/memmove.c" +#endif diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strrchr.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strrchr.c new file mode 100644 index 000000000..3cc8faa2e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strrchr.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2000, 2003, 2004 Free Software Foundation. + + Ensure all expected transformations of builtin strrchr and rindex + occur and perform correctly. + + Written by Jakub Jelinek, 11/7/2000. */ + +extern void abort (void); +extern char *strrchr (const char *, int); +extern char *rindex (const char *, int); + +char *bar = "hi world"; +int x = 7; + +void +main_test (void) +{ + const char *const foo = "hello world"; + + if (strrchr (foo, 'x')) + abort (); + if (strrchr (foo, 'o') != foo + 7) + abort (); + if (strrchr (foo, 'e') != foo + 1) + abort (); + if (strrchr (foo + 3, 'e')) + abort (); + if (strrchr (foo, '\0') != foo + 11) + abort (); + if (strrchr (bar, '\0') != bar + 8) + abort (); + if (strrchr (bar + 4, '\0') != bar + 8) + abort (); + if (strrchr (bar + (x++ & 3), '\0') != bar + 8) + abort (); + if (x != 8) + abort (); + /* Test only one instance of rindex since the code path is the same + as that of strrchr. */ + if (rindex ("hello", 'z') != 0) + abort (); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_strrchr (foo, 'o') != foo + 7) + abort (); + if (__builtin_rindex (foo, 'o') != foo + 7) + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strspn-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strspn-lib.c new file mode 100644 index 000000000..9e044d793 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strspn-lib.c @@ -0,0 +1 @@ +#include "lib/strspn.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strspn.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strspn.c new file mode 100644 index 000000000..4f2782a58 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strspn.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2000 Free Software Foundation. + + Ensure all expected transformations of builtin strspn occur and + perform correctly. + + Written by Kaveh R. Ghazi, 11/27/2000. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strspn (const char *, const char *); +extern char *strcpy (char *, const char *); + +void +main_test (void) +{ + const char *const s1 = "hello world"; + char dst[64], *d2; + + if (strspn (s1, "hello") != 5) + abort(); + if (strspn (s1+4, "hello") != 1) + abort(); + if (strspn (s1, "z") != 0) + abort(); + if (strspn (s1, "hello world") != 11) + abort(); + if (strspn (s1, "") != 0) + abort(); + strcpy (dst, s1); + if (strspn (dst, "") != 0) + abort(); + strcpy (dst, s1); d2 = dst; + if (strspn (++d2, "") != 0 || d2 != dst+1) + abort(); + strcpy (dst, s1); d2 = dst; + if (strspn (++d2+5, "") != 0 || d2 != dst+1) + abort(); + if (strspn ("", s1) != 0) + abort(); + strcpy (dst, s1); + if (strspn ("", dst) != 0) + abort(); + strcpy (dst, s1); d2 = dst; + if (strspn ("", ++d2) != 0 || d2 != dst+1) + abort(); + strcpy (dst, s1); d2 = dst; + if (strspn ("", ++d2+5) != 0 || d2 != dst+1) + abort(); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_strspn (s1, "hello") != 5) + abort(); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strstr-asm-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strstr-asm-lib.c new file mode 100644 index 000000000..a031a56a9 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strstr-asm-lib.c @@ -0,0 +1,37 @@ +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strlen(const char *); +extern char *strchr(const char *, int); +extern int strcmp(const char *, const char *); +extern int strncmp(const char *, const char *, size_t); +extern int inside_main; +extern const char *p; + +char * +my_strstr (const char *s1, const char *s2) +{ + const size_t len = strlen (s2); + +#ifdef __OPTIMIZE__ + /* If optimizing, we should be called only in the strstr (foo + 2, p) + case. All other cases should be optimized. */ + if (inside_main) + if (s2 != p || strcmp (s1, "hello world" + 2) != 0) + abort (); +#endif + if (len == 0) + return (char *) s1; + for (s1 = strchr (s1, *s2); s1; s1 = strchr (s1 + 1, *s2)) + if (strncmp (s1, s2, len) == 0) + return (char *) s1; + return (char *) 0; +} + +char * +strstr (const char *s1, const char *s2) +{ + if (inside_main) + abort (); + + return my_strstr (s1, s2); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strstr-asm.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strstr-asm.c new file mode 100644 index 000000000..3c3e45dfa --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strstr-asm.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2000, 2003 Free Software Foundation. + + Ensure all expected transformations of builtin strstr occur and + perform correctly in presence of redirect. */ + +#define ASMNAME(cname) ASMNAME2 (__USER_LABEL_PREFIX__, cname) +#define ASMNAME2(prefix, cname) STRING (prefix) cname +#define STRING(x) #x + +typedef __SIZE_TYPE__ size_t; +extern void abort (void); +extern char *strstr (const char *, const char *) + __asm (ASMNAME ("my_strstr")); + +const char *p = "rld", *q = "hello world"; + +void +main_test (void) +{ + const char *const foo = "hello world"; + + if (strstr (foo, "") != foo) + abort (); + if (strstr (foo + 4, "") != foo + 4) + abort (); + if (strstr (foo, "h") != foo) + abort (); + if (strstr (foo, "w") != foo + 6) + abort (); + if (strstr (foo + 6, "o") != foo + 7) + abort (); + if (strstr (foo + 1, "world") != foo + 6) + abort (); + if (strstr (foo + 2, p) != foo + 8) + abort (); + if (strstr (q, "") != q) + abort (); + if (strstr (q + 1, "o") != q + 4) + abort (); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_strstr (foo + 1, "world") != foo + 6) + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strstr-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strstr-lib.c new file mode 100644 index 000000000..591058de4 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strstr-lib.c @@ -0,0 +1 @@ +#include "lib/strstr.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strstr.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strstr.c new file mode 100644 index 000000000..ae503aa43 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strstr.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2000 Free Software Foundation. + + Ensure all expected transformations of builtin strstr occur and + perform correctly. + + Written by Kaveh R. Ghazi, 11/6/2000. */ + +extern void abort(void); +extern char *strstr (const char *, const char *); + +void +main_test (void) +{ + const char *const foo = "hello world"; + + if (strstr (foo, "") != foo) + abort(); + if (strstr (foo + 4, "") != foo + 4) + abort(); + if (strstr (foo, "h") != foo) + abort(); + if (strstr (foo, "w") != foo + 6) + abort(); + if (strstr (foo + 6, "o") != foo + 7) + abort(); + if (strstr (foo + 1, "world") != foo + 6) + abort(); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_strstr (foo + 1, "world") != foo + 6) + abort(); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/vsnprintf-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/vsnprintf-chk-lib.c new file mode 100644 index 000000000..9daf13e82 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/vsnprintf-chk-lib.c @@ -0,0 +1 @@ +#include "lib/chk.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/vsnprintf-chk.c b/gcc/testsuite/gcc.c-torture/execute/builtins/vsnprintf-chk.c new file mode 100644 index 000000000..8a3f37203 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/vsnprintf-chk.c @@ -0,0 +1,321 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation. + + Ensure builtin __vsnprintf_chk performs correctly. */ + +#include <stdarg.h> + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strlen(const char *); +extern void *memcpy (void *, const void *, size_t); +extern char *strcpy (char *, const char *); +extern int memcmp (const void *, const void *, size_t); +extern void *memset (void *, int, size_t); +extern int vsnprintf (char *, size_t, const char *, va_list); + +#include "chk.h" + +const char s1[] = "123"; +char p[32] = ""; +char *s2 = "defg"; +char *s3 = "FGH"; +char *s4; +size_t l1 = 1; +static char buffer[32]; +char * volatile ptr = "barf"; /* prevent constant propagation to happen when whole program assumptions are made. */ + +int +__attribute__((noinline)) +test1_sub (int i, ...) +{ + int ret = 0; + va_list ap; + va_start (ap, i); + switch (i) + { + case 0: + vsnprintf (buffer, 4, "foo", ap); + break; + case 1: + ret = vsnprintf (buffer, 4, "foo bar", ap); + break; + case 2: + vsnprintf (buffer, 32, "%s", ap); + break; + case 3: + ret = vsnprintf (buffer, 21, "%s", ap); + break; + case 4: + ret = vsnprintf (buffer, 4, "%d%d%d", ap); + break; + case 5: + ret = vsnprintf (buffer, 32, "%d%d%d", ap); + break; + case 6: + ret = vsnprintf (buffer, strlen (ptr) + 1, "%s", ap); + break; + case 7: + vsnprintf (buffer, l1 + 31, "%d - %c", ap); + break; + case 8: + vsnprintf (s4, l1 + 6, "%d - %c", ap); + break; + } + va_end (ap); + return ret; +} + +void +__attribute__((noinline)) +test1 (void) +{ + chk_calls = 0; + /* vsnprintf_disallowed = 1; */ + + memset (buffer, 'A', 32); + test1_sub (0); + if (memcmp (buffer, "foo", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + if (test1_sub (1) != 7) + abort (); + if (memcmp (buffer, "foo", 4) || buffer[4] != 'A') + abort (); + + vsnprintf_disallowed = 0; + + memset (buffer, 'A', 32); + test1_sub (2, "bar"); + if (memcmp (buffer, "bar", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + if (test1_sub (3, "bar") != 3) + abort (); + if (memcmp (buffer, "bar", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + if (test1_sub (4, (int) l1, (int) l1 + 1, (int) l1 + 12) != 4) + abort (); + if (memcmp (buffer, "121", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + if (test1_sub (5, (int) l1, (int) l1 + 1, (int) l1 + 12) != 4) + abort (); + if (memcmp (buffer, "1213", 5) || buffer[5] != 'A') + abort (); + + if (chk_calls) + abort (); + + memset (buffer, 'A', 32); + test1_sub (6, ptr); + if (memcmp (buffer, "barf", 5) || buffer[5] != 'A') + abort (); + + memset (buffer, 'A', 32); + test1_sub (7, (int) l1 + 27, *ptr); + if (memcmp (buffer, "28 - b\0AAAAA", 12)) + abort (); + + if (chk_calls != 2) + abort (); + chk_calls = 0; + + memset (s4, 'A', 32); + test1_sub (8, (int) l1 - 17, ptr[1]); + if (memcmp (s4, "-16 - \0AAA", 10)) + abort (); + if (chk_calls) + abort (); +} + +void +__attribute__((noinline)) +test2_sub (int i, ...) +{ + va_list ap; + struct A { char buf1[10]; char buf2[10]; } a; + char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4]; + char buf3[20]; + int j; + + va_start (ap, i); + /* The following calls should do runtime checking + - length is not known, but destination is. */ + switch (i) + { + case 0: + vsnprintf (a.buf1 + 2, l1, "%s", ap); + break; + case 1: + vsnprintf (r, l1 + 4, "%s%c", ap); + break; + case 2: + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + vsnprintf (r, strlen (s2) - 2, "%c %s", ap); + break; + case 3: + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + vsnprintf (r + 2, l1, s3 + 3, ap); + break; + case 4: + case 7: + r = buf3; + for (j = 0; j < 4; ++j) + { + if (j == l1 - 1) + r = &a.buf1[1]; + else if (j == l1) + r = &a.buf2[7]; + else if (j == l1 + 1) + r = &buf3[5]; + else if (j == l1 + 2) + r = &a.buf1[9]; + } + if (i == 4) + vsnprintf (r, l1, s2 + 4, ap); + else + vsnprintf (r, 1, "a", ap); + break; + case 5: + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + vsnprintf (r, l1 + 3, "%s", ap); + break; + case 6: + vsnprintf (a.buf1 + 2, 4, "", ap); + break; + case 8: + vsnprintf (s4, 3, "%s %d", ap); + break; + } + va_end (ap); +} + +/* Test whether compile time checking is done where it should + and so is runtime object size checking. */ +void +__attribute__((noinline)) +test2 (void) +{ + /* The following calls should do runtime checking + - length is not known, but destination is. */ + chk_calls = 0; + test2_sub (0, s3 + 3); + test2_sub (1, s3 + 3, s3[3]); + test2_sub (2, s2[2], s2 + 4); + test2_sub (3); + test2_sub (4); + test2_sub (5, s1 + 1); + if (chk_calls != 6) + abort (); + + /* Following have known destination and known source length, + so if optimizing certainly shouldn't result in the checking + variants. */ + chk_calls = 0; + /* vsnprintf_disallowed = 1; */ + test2_sub (6); + test2_sub (7); + vsnprintf_disallowed = 0; + /* Unknown destination and source, no checking. */ + test2_sub (8, s3, 0); + if (chk_calls) + abort (); +} + +void +__attribute__((noinline)) +test3_sub (int i, ...) +{ + va_list ap; + struct A { char buf1[10]; char buf2[10]; } a; + char buf3[20]; + + va_start (ap, i); + /* The following calls should do runtime checking + - source length is not known, but destination is. */ + switch (i) + { + case 0: + vsnprintf (&a.buf2[9], l1 + 1, "%c%s", ap); + break; + case 1: + vsnprintf (&a.buf2[7], l1 + 30, "%s%c", ap); + break; + case 2: + vsnprintf (&a.buf2[7], l1 + 3, "%d", ap); + break; + case 3: + vsnprintf (&buf3[17], l1 + 3, "%s", ap); + break; + case 4: + vsnprintf (&buf3[19], 2, "a", ap); + break; + case 5: + vsnprintf (&buf3[16], 5, "a", ap); + break; + } + va_end (ap); +} + +/* Test whether runtime and/or compile time checking catches + buffer overflows. */ +void +__attribute__((noinline)) +test3 (void) +{ + chk_fail_allowed = 1; + /* Runtime checks. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + test3_sub (0, s2[3], s2 + 4); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + test3_sub (1, s3 + strlen (s3) - 2, *s3); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + test3_sub (2, (int) l1 + 9999); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + test3_sub (3, "abc"); + abort (); + } + /* This should be detectable at compile time already. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + test3_sub (4); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + test3_sub (5); + abort (); + } + chk_fail_allowed = 0; +} + +void +main_test (void) +{ +#ifndef __OPTIMIZE__ + /* Object size checking is only intended for -O[s123]. */ + return; +#endif + __asm ("" : "=r" (s2) : "0" (s2)); + __asm ("" : "=r" (s3) : "0" (s3)); + __asm ("" : "=r" (l1) : "0" (l1)); + s4 = p; + test1 (); + test2 (); + test3 (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/vsprintf-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/vsprintf-chk-lib.c new file mode 100644 index 000000000..9daf13e82 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/vsprintf-chk-lib.c @@ -0,0 +1 @@ +#include "lib/chk.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/vsprintf-chk.c b/gcc/testsuite/gcc.c-torture/execute/builtins/vsprintf-chk.c new file mode 100644 index 000000000..5649b9e90 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/vsprintf-chk.c @@ -0,0 +1,290 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation. + + Ensure builtin __vsprintf_chk performs correctly. */ + +#include <stdarg.h> + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern size_t strlen(const char *); +extern void *memcpy (void *, const void *, size_t); +extern char *strcpy (char *, const char *); +extern int memcmp (const void *, const void *, size_t); +extern void *memset (void *, int, size_t); +extern int vsprintf (char *, const char *, va_list); + +#include "chk.h" + +const char s1[] = "123"; +char p[32] = ""; +char *s2 = "defg"; +char *s3 = "FGH"; +char *s4; +size_t l1 = 1; +static char buffer[32]; +char * volatile ptr = "barf"; /* prevent constant propagation to happen when whole program assumptions are made. */ + +int +__attribute__((noinline)) +test1_sub (int i, ...) +{ + int ret = 0; + va_list ap; + va_start (ap, i); + switch (i) + { + case 0: + vsprintf (buffer, "foo", ap); + break; + case 1: + ret = vsprintf (buffer, "foo", ap); + break; + case 2: + vsprintf (buffer, "%s", ap); + break; + case 3: + ret = vsprintf (buffer, "%s", ap); + break; + case 4: + vsprintf (buffer, "%d - %c", ap); + break; + case 5: + vsprintf (s4, "%d - %c", ap); + break; + } + va_end (ap); + return ret; +} + +void +__attribute__((noinline)) +test1 (void) +{ + chk_calls = 0; + vsprintf_disallowed = 1; + + memset (buffer, 'A', 32); + test1_sub (0); + if (memcmp (buffer, "foo", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + if (test1_sub (1) != 3) + abort (); + if (memcmp (buffer, "foo", 4) || buffer[4] != 'A') + abort (); + + if (chk_calls) + abort (); + vsprintf_disallowed = 0; + + memset (buffer, 'A', 32); + test1_sub (2, "bar"); + if (memcmp (buffer, "bar", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + if (test1_sub (3, "bar") != 3) + abort (); + if (memcmp (buffer, "bar", 4) || buffer[4] != 'A') + abort (); + + memset (buffer, 'A', 32); + test1_sub (2, ptr); + if (memcmp (buffer, "barf", 5) || buffer[5] != 'A') + abort (); + + memset (buffer, 'A', 32); + test1_sub (4, (int) l1 + 27, *ptr); + if (memcmp (buffer, "28 - b\0AAAAA", 12)) + abort (); + + if (chk_calls != 4) + abort (); + chk_calls = 0; + + test1_sub (5, (int) l1 - 17, ptr[1]); + if (memcmp (s4, "-16 - a", 8)) + abort (); + if (chk_calls) + abort (); +} + +void +__attribute__((noinline)) +test2_sub (int i, ...) +{ + va_list ap; + struct A { char buf1[10]; char buf2[10]; } a; + char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4]; + char buf3[20]; + int j; + + va_start (ap, i); + /* The following calls should do runtime checking + - source length is not known, but destination is. */ + switch (i) + { + case 0: + vsprintf (a.buf1 + 2, "%s", ap); + break; + case 1: + vsprintf (r, "%s%c", ap); + break; + case 2: + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + vsprintf (r, "%c %s", ap); + break; + case 3: + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + vsprintf (r + 2, s3 + 3, ap); + break; + case 4: + case 7: + r = buf3; + for (j = 0; j < 4; ++j) + { + if (j == l1 - 1) + r = &a.buf1[1]; + else if (j == l1) + r = &a.buf2[7]; + else if (j == l1 + 1) + r = &buf3[5]; + else if (j == l1 + 2) + r = &a.buf1[9]; + } + if (i == 4) + vsprintf (r, s2 + 4, ap); + else + vsprintf (r, "a", ap); + break; + case 5: + r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; + vsprintf (r, "%s", ap); + break; + case 6: + vsprintf (a.buf1 + 2, "", ap); + break; + case 8: + vsprintf (s4, "%s %d", ap); + break; + } + va_end (ap); +} + +/* Test whether compile time checking is done where it should + and so is runtime object size checking. */ +void +__attribute__((noinline)) +test2 (void) +{ + /* The following calls should do runtime checking + - source length is not known, but destination is. */ + chk_calls = 0; + test2_sub (0, s3 + 3); + test2_sub (1, s3 + 3, s3[3]); + test2_sub (2, s2[2], s2 + 4); + test2_sub (3); + test2_sub (4); + test2_sub (5, s1 + 1); + if (chk_calls != 6) + abort (); + + /* Following have known destination and known source length, + so if optimizing certainly shouldn't result in the checking + variants. */ + chk_calls = 0; + vsprintf_disallowed = 1; + test2_sub (6); + test2_sub (7); + vsprintf_disallowed = 0; + /* Unknown destination and source, no checking. */ + test2_sub (8, s3, 0); + if (chk_calls) + abort (); +} + +void +__attribute__((noinline)) +test3_sub (int i, ...) +{ + va_list ap; + struct A { char buf1[10]; char buf2[10]; } a; + char buf3[20]; + + va_start (ap, i); + /* The following calls should do runtime checking + - source length is not known, but destination is. */ + switch (i) + { + case 0: + vsprintf (&a.buf2[9], "%c%s", ap); + break; + case 1: + vsprintf (&a.buf2[7], "%s%c", ap); + break; + case 2: + vsprintf (&a.buf2[7], "%d", ap); + break; + case 3: + vsprintf (&buf3[17], "%s", ap); + break; + case 4: + vsprintf (&buf3[19], "a", ap); + break; + } + va_end (ap); +} + +/* Test whether runtime and/or compile time checking catches + buffer overflows. */ +void +__attribute__((noinline)) +test3 (void) +{ + chk_fail_allowed = 1; + /* Runtime checks. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + test3_sub (0, s2[3], s2 + 4); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + test3_sub (1, s3 + strlen (s3) - 2, *s3); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + test3_sub (2, (int) l1 + 9999); + abort (); + } + if (__builtin_setjmp (chk_fail_buf) == 0) + { + test3_sub (3, "abc"); + abort (); + } + /* This should be detectable at compile time already. */ + if (__builtin_setjmp (chk_fail_buf) == 0) + { + test3_sub (4); + abort (); + } + chk_fail_allowed = 0; +} + +void +main_test (void) +{ +#ifndef __OPTIMIZE__ + /* Object size checking is only intended for -O[s123]. */ + return; +#endif + __asm ("" : "=r" (s2) : "0" (s2)); + __asm ("" : "=r" (s3) : "0" (s3)); + __asm ("" : "=r" (l1) : "0" (l1)); + s4 = p; + test1 (); + test2 (); + test3 (); +} |