diff options
| author | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-06-27 12:17:39 +0000 |
|---|---|---|
| committer | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-06-27 12:17:39 +0000 |
| commit | 0a39fd5408943300a03d40afe1f6e5b59ae31816 (patch) | |
| tree | bb3939873bf2cf5cb7bd56f678141658affb0021 /gcc/testsuite/gcc.c-torture/execute | |
| parent | f68ab9c535c26d62063f272878415869effc0ef6 (diff) | |
| download | ppe42-gcc-0a39fd5408943300a03d40afe1f6e5b59ae31816.tar.gz ppe42-gcc-0a39fd5408943300a03d40afe1f6e5b59ae31816.zip | |
* builtin-attrs.def (DEF_ATTR_FOR_INT): Add for 5 and 6.
(DEF_LIST_INT_INT): Add for 4,0, 4,5, 5,0, 5,6.
(ATTR_NOTHROW_NONNULL_4, ATTR_NOTHROW_NONNULL_5): Define.
(ATTR_FORMAT_PRINTF_4_0, ATTR_FORMAT_PRINTF_4_5,
ATTR_FORMAT_PRINTF_5_0, ATTR_FORMAT_PRINTF_5_6): Define.
* builtins.c: Include tree-flow.h.
(expand_builtin_mempcpy, expand_builtin_memmove): Comment fixes.
(expand_builtin_object_size, expand_builtin_memory_chk,
maybe_emit_chk_warning, maybe_emit_sprintf_chk_warning,
compute_object_offset, compute_builtin_object_size,
fold_builtin_object_size): New functions.
(expand_builtin): Handle BUILT_IN_OBJECT_SIZE and BUILT_IN_*_CHK.
(fold_builtin_1): Likewise. Handle BUILT_IN_{,V}{,F}PRINTF
and BUILT_IN_{,F}PRINTF_UNLOCKED.
(fold_builtin_memory_chk, fold_builtin_stxcpy_chk,
fold_builtin_strncpy_chk, fold_builtin_strcat_chk,
fold_builtin_strncat_chk, fold_builtin_sprintf_chk,
fold_builtin_snprintf_chk, fold_builtin_printf, fold_builtin_fprintf):
New functions.
* builtins.def (BUILT_IN_OBJECT_SIZE, BUILT_IN_MEMCPY_CHK,
BUILT_IN_MEMMOVE_CHK, BUILT_IN_MEMPCPY_CHK, BUILT_IN_MEMSET_CHK,
BUILT_IN_STPCPY_CHK, BUILT_IN_STRCAT_CHK, BUILT_IN_STRCPY_CHK,
BUILT_IN_STRNCAT_CHK, BUILT_IN_STRNCPY_CHK, BUILT_IN_SNPRINTF_CHK,
BUILT_IN_SPRINTF_CHK, BUILT_IN_VSNPRINTF_CHK, BUILT_IN_VSPRINTF_CHK,
BUILT_IN_FPRINTF_CHK, BUILT_IN_PRINTF_CHK, BUILT_IN_VFPRINTF_CHK,
BUILT_IN_VPRINTF_CHK): New builtins.
* builtin-types.def (DEF_FUNCTION_TYPE_5, DEF_FUNCTION_TYPE_VAR_4):
Document.
(BT_FN_SIZE_CONST_PTR_INT, BT_FN_INT_INT_CONST_STRING_VALIST_ARG,
BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, BT_FN_PTR_PTR_INT_SIZE_SIZE,
BT_FN_STRING_STRING_CONST_STRING_SIZE_SIZE,
BT_FN_INT_FILEPTR_INT_CONST_STRING_VALIST_ARG,
BT_FN_INT_STRING_INT_SIZE_CONST_STRING_VALIST_ARG,
BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VALIST_ARG,
BT_FN_INT_INT_CONST_STRING_VAR, BT_FN_INT_FILEPTR_INT_CONST_STRING_VAR,
BT_FN_INT_STRING_INT_SIZE_CONST_STRING_VAR,
BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VAR): New types.
* c-common.c (DEF_FUNCTION_TYPE_5, DEF_FUNCTION_TYPE_6,
DEF_FUNCTION_TYPE_VAR_4, DEF_FUNCTION_TYPE_VAR_5): Define.
* Makefile.in (OBJS-common): Add tree-object-size.o.
(tree-object-size.o): Add dependencies.
* tree-pass.h (pass_object_sizes): Add.
* tree-optimize.c (init_tree_optimization_passes): Add
pass_object_sizes.
* tree-object-size.c: New file.
* tree.h (fold_builtin_memory_chk, fold_builtin_stxcpy_chk,
fold_builtin_strncpy_chk, fold_builtin_snprintf_chk,
compute_builtin_object_size, init_object_sizes, fini_object_sizes):
New prototypes.
* tree-ssa-ccp.c (get_strlen): Rename to ...
(get_maxval_strlen): ...this function. Handle also computing of maximum
string length and maximum integral value.
(ccp_fold_builtin): Handle BUILT_IN_*_CHK. Use get_maxval_strlen
instead of get_strlen. Pass CALLEE and ARGLIST variables to the
folding functions instead of computing them again.
(execute_fold_all_builtins): Retry ccp_fold_builtin if a builtin changed
into some other builtin.
* doc/extend.texi (Object Size Checking): Document.
* gcc.c-torture/execute/builtins/lib/main.c (abort): Add prototype.
* gcc.c-torture/execute/builtins/lib/strncat.c (strncat): Avoid
testing uninitialized var.
* gcc.c-torture/execute/builtins/chk.h: New.
* gcc.c-torture/execute/builtins/lib/chk.c: New.
* gcc.c-torture/execute/builtins/memcpy-chk.c: New test.
* gcc.c-torture/execute/builtins/memcpy-chk-lib.c: New.
* gcc.c-torture/execute/builtins/memmove-chk.c: New test.
* gcc.c-torture/execute/builtins/memmove-chk-lib.c: New.
* gcc.c-torture/execute/builtins/mempcpy-chk.c: New test.
* gcc.c-torture/execute/builtins/mempcpy-chk-lib.c: New.
* gcc.c-torture/execute/builtins/memset-chk.c: New test.
* gcc.c-torture/execute/builtins/memset-chk-lib.c: New.
* gcc.c-torture/execute/builtins/snprintf-chk.c: New test.
* gcc.c-torture/execute/builtins/snprintf-chk-lib.c: New.
* gcc.c-torture/execute/builtins/sprintf-chk.c: New test.
* gcc.c-torture/execute/builtins/sprintf-chk-lib.c: New.
* gcc.c-torture/execute/builtins/stpcpy-chk.c: New test.
* gcc.c-torture/execute/builtins/stpcpy-chk-lib.c: New.
* gcc.c-torture/execute/builtins/strcat-chk.c: New test.
* gcc.c-torture/execute/builtins/strcat-chk-lib.c: New.
* gcc.c-torture/execute/builtins/strcpy-chk.c: New test.
* gcc.c-torture/execute/builtins/strcpy-chk-lib.c: New.
* gcc.c-torture/execute/builtins/strncat-chk.c: New test.
* gcc.c-torture/execute/builtins/strncat-chk-lib.c: New.
* gcc.c-torture/execute/builtins/strncpy-chk.c: New test.
* gcc.c-torture/execute/builtins/strncpy-chk-lib.c: New.
* gcc.c-torture/execute/builtins/vsnprintf-chk.c: New test.
* gcc.c-torture/execute/builtins/vsnprintf-chk-lib.c: New.
* gcc.c-torture/execute/builtins/vsprintf-chk.c: New test.
* gcc.c-torture/execute/builtins/vsprintf-chk-lib.c: New.
* gcc.dg/builtin-object-size-1.c: New test.
* gcc.dg/builtin-object-size-2.c: New test.
* gcc.dg/builtin-object-size-3.c: New test.
* gcc.dg/builtin-object-size-4.c: New test.
* gcc.dg/builtin-object-size-5.c: New test.
* gcc.dg/builtin-stringop-chk-1.c: New test.
* gcc.dg/builtin-stringop-chk-2.c: New test.
* gcc.dg/tree-ssa/builtin-fprintf-1.c: New test.
* gcc.dg/tree-ssa/builtin-fprintf-chk-1.c: New test.
* gcc.dg/tree-ssa/builtin-printf-1.c: New test.
* gcc.dg/tree-ssa/builtin-printf-chk-1.c: New test.
* gcc.dg/tree-ssa/builtin-vfprintf-1.c: New test.
* gcc.dg/tree-ssa/builtin-vfprintf-chk-1.c: New test.
* gcc.dg/tree-ssa/builtin-vprintf-1.c: New test.
* gcc.dg/tree-ssa/builtin-vprintf-chk-1.c: New test.
* gcc.c-torture/execute/printf-1.c: New test.
* gcc.c-torture/execute/fprintf-1.c: New test.
* gcc.c-torture/execute/vprintf-1.c: New test.
* gcc.c-torture/execute/vfprintf-1.c: New test.
* gcc.c-torture/execute/printf-chk-1.c: New test.
* gcc.c-torture/execute/fprintf-chk-1.c: New test.
* gcc.c-torture/execute/vprintf-chk-1.c: New test.
* gcc.c-torture/execute/vfprintf-chk-1.c: New test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@101352 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/testsuite/gcc.c-torture/execute')
38 files changed, 5418 insertions, 1 deletions
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 00000000000..dfef410c61b --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/chk.h @@ -0,0 +1,81 @@ +#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; 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 00000000000..eb305d47229 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/chk.c @@ -0,0 +1,472 @@ +#include <stdarg.h> + +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; +} + +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; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/main.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/main.c index 1ca606565a8..a9bb6c6b890 100644 --- a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/main.c +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/main.c @@ -1,5 +1,6 @@ extern void abort(void); extern void main_test (void); +extern void abort (void); int inside_main; int diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strncat.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strncat.c index 051dc46c723..290d4cf49bb 100644 --- a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strncat.c +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/strncat.c @@ -13,11 +13,12 @@ strncat (char *s1, const char *s2, size_t n) abort(); #endif while (*s1) s1++; + c = '\0'; while (n > 0) { c = *s2++; *s1++ = c; - if (c == 0) + if (c == '\0') return dest; n--; } 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 00000000000..9daf13e827b --- /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 00000000000..28f7ae785f6 --- /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] = ""; +char *s2 = "defg"; +char *s3 = "FGH"; +size_t l1 = 1; + +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-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memmove-chk-lib.c new file mode 100644 index 00000000000..9daf13e827b --- /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 00000000000..12272272ca6 --- /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] = ""; +char *s2 = "defg"; +char *s3 = "FGH"; +size_t l1 = 1; + +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/mempcpy-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-chk-lib.c new file mode 100644 index 00000000000..9daf13e827b --- /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 00000000000..a59d59bd85d --- /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] = ""; +char *s2 = "defg"; +char *s3 = "FGH"; +size_t l1 = 1; + +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/memset-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memset-chk-lib.c new file mode 100644 index 00000000000..9daf13e827b --- /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 00000000000..a8f09a73931 --- /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; +size_t l1 = 1; +char *s3 = "FGH"; +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/snprintf-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/snprintf-chk-lib.c new file mode 100644 index 00000000000..9daf13e827b --- /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 00000000000..e6ddc086038 --- /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 *ptr = "barf"; + +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 00000000000..9daf13e827b --- /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 00000000000..95d2a9d2826 --- /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" + +const char s1[] = "123"; +char p[32] = ""; +char *s2 = "defg"; +char *s3 = "FGH"; +char *s4; +size_t l1 = 1; +static char buffer[32]; +char *ptr = "barf"; + +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/stpcpy-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/stpcpy-chk-lib.c new file mode 100644 index 00000000000..9daf13e827b --- /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 00000000000..b292c0aec87 --- /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" + +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 00000000000..9daf13e827b --- /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 00000000000..fea3184e8f5 --- /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/strcpy-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-chk-lib.c new file mode 100644 index 00000000000..9daf13e827b --- /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 00000000000..002dd19500e --- /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" + +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/strncat-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strncat-chk-lib.c new file mode 100644 index 00000000000..9daf13e827b --- /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 00000000000..8904df14aee --- /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/strncpy-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strncpy-chk-lib.c new file mode 100644 index 00000000000..9daf13e827b --- /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 00000000000..46f3374c4dd --- /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 *s2 = "defg"; +char *s3 = "FGH"; +char *s4; +size_t l1 = 1; +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/vsnprintf-chk-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/vsnprintf-chk-lib.c new file mode 100644 index 00000000000..9daf13e827b --- /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 00000000000..8c7d72f391d --- /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 *ptr = "barf"; + +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 00000000000..9daf13e827b --- /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 00000000000..5c150901800 --- /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 *ptr = "barf"; + +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 (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/fprintf-1.c b/gcc/testsuite/gcc.c-torture/execute/fprintf-1.c new file mode 100644 index 00000000000..f16252b1e8e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/fprintf-1.c @@ -0,0 +1,23 @@ +#include <stdio.h> +#include <stdlib.h> + +int +main (void) +{ +#define test(ret, args...) \ + fprintf (stdout, args); \ + if (fprintf (stdout, args) != ret) \ + abort (); + test (5, "hello"); + test (6, "hello\n"); + test (1, "a"); + test (0, ""); + test (5, "%s", "hello"); + test (6, "%s", "hello\n"); + test (1, "%s", "a"); + test (0, "%s", ""); + test (1, "%c", 'x'); + test (7, "%s\n", "hello\n"); + test (2, "%d\n", 0); + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/fprintf-chk-1.c b/gcc/testsuite/gcc.c-torture/execute/fprintf-chk-1.c new file mode 100644 index 00000000000..918ff8e5689 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/fprintf-chk-1.c @@ -0,0 +1,49 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +volatile int should_optimize; + +int +__attribute__((noinline)) +__fprintf_chk (FILE *f, int flag, const char *fmt, ...) +{ + va_list ap; + int ret; +#ifdef __OPTIMIZE__ + if (should_optimize) + abort (); +#endif + should_optimize = 1; + va_start (ap, fmt); + ret = vfprintf (f, fmt, ap); + va_end (ap); + return ret; +} + +int +main (void) +{ +#define test(ret, opt, args...) \ + should_optimize = opt; \ + __fprintf_chk (stdout, 1, args); \ + if (!should_optimize) \ + abort (); \ + should_optimize = 0; \ + if (__fprintf_chk (stdout, 1, args) != ret) \ + abort (); \ + if (!should_optimize) \ + abort (); + test (5, 1, "hello"); + test (6, 1, "hello\n"); + test (1, 1, "a"); + test (0, 1, ""); + test (5, 1, "%s", "hello"); + test (6, 1, "%s", "hello\n"); + test (1, 1, "%s", "a"); + test (0, 1, "%s", ""); + test (1, 1, "%c", 'x'); + test (7, 0, "%s\n", "hello\n"); + test (2, 0, "%d\n", 0); + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/printf-1.c b/gcc/testsuite/gcc.c-torture/execute/printf-1.c new file mode 100644 index 00000000000..0ffcd5d443b --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/printf-1.c @@ -0,0 +1,23 @@ +#include <stdio.h> +#include <stdlib.h> + +int +main (void) +{ +#define test(ret, args...) \ + printf (args); \ + if (printf (args) != ret) \ + abort (); + test (5, "hello"); + test (6, "hello\n"); + test (1, "a"); + test (0, ""); + test (5, "%s", "hello"); + test (6, "%s", "hello\n"); + test (1, "%s", "a"); + test (0, "%s", ""); + test (1, "%c", 'x'); + test (7, "%s\n", "hello\n"); + test (2, "%d\n", 0); + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/printf-chk-1.c b/gcc/testsuite/gcc.c-torture/execute/printf-chk-1.c new file mode 100644 index 00000000000..8f9a79c5c57 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/printf-chk-1.c @@ -0,0 +1,49 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +volatile int should_optimize; + +int +__attribute__((noinline)) +__printf_chk (int flag, const char *fmt, ...) +{ + va_list ap; + int ret; +#ifdef __OPTIMIZE__ + if (should_optimize) + abort (); +#endif + should_optimize = 1; + va_start (ap, fmt); + ret = vprintf (fmt, ap); + va_end (ap); + return ret; +} + +int +main (void) +{ +#define test(ret, opt, args...) \ + should_optimize = opt; \ + __printf_chk (1, args); \ + if (!should_optimize) \ + abort (); \ + should_optimize = 0; \ + if (__printf_chk (1, args) != ret) \ + abort (); \ + if (!should_optimize) \ + abort (); + test (5, 0, "hello"); + test (6, 1, "hello\n"); + test (1, 1, "a"); + test (0, 1, ""); + test (5, 0, "%s", "hello"); + test (6, 1, "%s", "hello\n"); + test (1, 1, "%s", "a"); + test (0, 1, "%s", ""); + test (1, 1, "%c", 'x'); + test (7, 1, "%s\n", "hello\n"); + test (2, 0, "%d\n", 0); + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/vfprintf-1.c b/gcc/testsuite/gcc.c-torture/execute/vfprintf-1.c new file mode 100644 index 00000000000..c0038042542 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/vfprintf-1.c @@ -0,0 +1,53 @@ +#ifndef test +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +void +inner (int x, ...) +{ + va_list ap, ap2; + va_start (ap, x); + va_start (ap2, x); + + switch (x) + { +#define test(n, ret, fmt, args) \ + case n: \ + vfprintf (stdout, fmt, ap); \ + if (vfprintf (stdout, fmt, ap2) != ret) \ + abort (); \ + break; +#include "vfprintf-1.c" +#undef test + default: + abort (); + } + + va_end (ap); + va_end (ap2); +} + +int +main (void) +{ +#define test(n, ret, fmt, args) \ + inner args; +#include "vfprintf-1.c" +#undef test + return 0; +} + +#else + test (0, 5, "hello", (0)); + test (1, 6, "hello\n", (1)); + test (2, 1, "a", (2)); + test (3, 0, "", (3)); + test (4, 5, "%s", (4, "hello")); + test (5, 6, "%s", (5, "hello\n")); + test (6, 1, "%s", (6, "a")); + test (7, 0, "%s", (7, "")); + test (8, 1, "%c", (8, 'x')); + test (9, 7, "%s\n", (9, "hello\n")); + test (10, 2, "%d\n", (10, 0)); +#endif diff --git a/gcc/testsuite/gcc.c-torture/execute/vfprintf-chk-1.c b/gcc/testsuite/gcc.c-torture/execute/vfprintf-chk-1.c new file mode 100644 index 00000000000..f8f964c7e9a --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/vfprintf-chk-1.c @@ -0,0 +1,73 @@ +#ifndef test +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +volatile int should_optimize; + +int +__attribute__((noinline)) +__vfprintf_chk (FILE *f, int flag, const char *fmt, va_list ap) +{ +#ifdef __OPTIMIZE__ + if (should_optimize) + abort (); +#endif + should_optimize = 1; + return vfprintf (f, fmt, ap); +} + +void +inner (int x, ...) +{ + va_list ap, ap2; + va_start (ap, x); + va_start (ap2, x); + + switch (x) + { +#define test(n, ret, opt, fmt, args) \ + case n: \ + should_optimize = opt; \ + __vfprintf_chk (stdout, 1, fmt, ap); \ + if (! should_optimize) \ + abort (); \ + should_optimize = 0; \ + if (__vfprintf_chk (stdout, 1, fmt, ap2) != ret) \ + abort (); \ + if (! should_optimize) \ + abort (); \ + break; +#include "vfprintf-chk-1.c" +#undef test + default: + abort (); + } + + va_end (ap); + va_end (ap2); +} + +int +main (void) +{ +#define test(n, ret, opt, fmt, args) \ + inner args; +#include "vfprintf-chk-1.c" +#undef test + return 0; +} + +#else + test (0, 5, 1, "hello", (0)); + test (1, 6, 1, "hello\n", (1)); + test (2, 1, 1, "a", (2)); + test (3, 0, 1, "", (3)); + test (4, 5, 0, "%s", (4, "hello")); + test (5, 6, 0, "%s", (5, "hello\n")); + test (6, 1, 0, "%s", (6, "a")); + test (7, 0, 0, "%s", (7, "")); + test (8, 1, 0, "%c", (8, 'x')); + test (9, 7, 0, "%s\n", (9, "hello\n")); + test (10, 2, 0, "%d\n", (10, 0)); +#endif diff --git a/gcc/testsuite/gcc.c-torture/execute/vprintf-1.c b/gcc/testsuite/gcc.c-torture/execute/vprintf-1.c new file mode 100644 index 00000000000..9f1b8bf67aa --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/vprintf-1.c @@ -0,0 +1,53 @@ +#ifndef test +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +void +inner (int x, ...) +{ + va_list ap, ap2; + va_start (ap, x); + va_start (ap2, x); + + switch (x) + { +#define test(n, ret, fmt, args) \ + case n: \ + vprintf (fmt, ap); \ + if (vprintf (fmt, ap2) != ret) \ + abort (); \ + break; +#include "vprintf-1.c" +#undef test + default: + abort (); + } + + va_end (ap); + va_end (ap2); +} + +int +main (void) +{ +#define test(n, ret, fmt, args) \ + inner args; +#include "vprintf-1.c" +#undef test + return 0; +} + +#else + test (0, 5, "hello", (0)); + test (1, 6, "hello\n", (1)); + test (2, 1, "a", (2)); + test (3, 0, "", (3)); + test (4, 5, "%s", (4, "hello")); + test (5, 6, "%s", (5, "hello\n")); + test (6, 1, "%s", (6, "a")); + test (7, 0, "%s", (7, "")); + test (8, 1, "%c", (8, 'x')); + test (9, 7, "%s\n", (9, "hello\n")); + test (10, 2, "%d\n", (10, 0)); +#endif diff --git a/gcc/testsuite/gcc.c-torture/execute/vprintf-chk-1.c b/gcc/testsuite/gcc.c-torture/execute/vprintf-chk-1.c new file mode 100644 index 00000000000..ca62f8b9fe2 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/vprintf-chk-1.c @@ -0,0 +1,73 @@ +#ifndef test +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +volatile int should_optimize; + +int +__attribute__((noinline)) +__vprintf_chk (int flag, const char *fmt, va_list ap) +{ +#ifdef __OPTIMIZE__ + if (should_optimize) + abort (); +#endif + should_optimize = 1; + return vprintf (fmt, ap); +} + +void +inner (int x, ...) +{ + va_list ap, ap2; + va_start (ap, x); + va_start (ap2, x); + + switch (x) + { +#define test(n, ret, opt, fmt, args) \ + case n: \ + should_optimize = opt; \ + __vprintf_chk (1, fmt, ap); \ + if (! should_optimize) \ + abort (); \ + should_optimize = 0; \ + if (__vprintf_chk (1, fmt, ap2) != ret) \ + abort (); \ + if (! should_optimize) \ + abort (); \ + break; +#include "vprintf-chk-1.c" +#undef test + default: + abort (); + } + + va_end (ap); + va_end (ap2); +} + +int +main (void) +{ +#define test(n, ret, opt, fmt, args) \ + inner args; +#include "vprintf-chk-1.c" +#undef test + return 0; +} + +#else + test (0, 5, 0, "hello", (0)); + test (1, 6, 1, "hello\n", (1)); + test (2, 1, 1, "a", (2)); + test (3, 0, 1, "", (3)); + test (4, 5, 0, "%s", (4, "hello")); + test (5, 6, 0, "%s", (5, "hello\n")); + test (6, 1, 0, "%s", (6, "a")); + test (7, 0, 0, "%s", (7, "")); + test (8, 1, 0, "%c", (8, 'x')); + test (9, 7, 0, "%s\n", (9, "hello\n")); + test (10, 2, 0, "%d\n", (10, 0)); +#endif |

