builtin-attrs.def (DEF_ATTR_FOR_INT): Add for 5 and 6.
* 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. From-SVN: r101352
This commit is contained in:
parent
de16a5b6a4
commit
10a0d49571
67 changed files with 10572 additions and 66 deletions
|
@ -1,5 +1,64 @@
|
|||
2005-06-27 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* 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.
|
||||
|
||||
* regrename.c (copy_value): Fix comment.
|
||||
|
||||
* toplev.c (process_options): Use if (FRAME_GROWS_DOWNWARD)
|
||||
|
|
|
@ -956,7 +956,7 @@ OBJS-common = \
|
|||
rtl-profile.o tree-profile.o rtlhooks.o cfgexpand.o lambda-mat.o \
|
||||
lambda-trans.o lambda-code.o tree-loop-linear.o tree-ssa-sink.o \
|
||||
tree-vrp.o tree-stdarg.o tree-cfgcleanup.o tree-ssa-reassoc.o \
|
||||
tree-ssa-structalias.o
|
||||
tree-ssa-structalias.o tree-object-size.o
|
||||
|
||||
|
||||
OBJS-md = $(out_object_file)
|
||||
|
@ -1945,6 +1945,9 @@ tree-loop-linear.o: tree-loop-linear.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
|
|||
tree-stdarg.o: tree-stdarg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
|
||||
$(TREE_H) function.h $(DIAGNOSTIC_H) $(TREE_FLOW_H) tree-pass.h \
|
||||
tree-stdarg.h $(TARGET_H) langhooks.h
|
||||
tree-object-size.o: tree-object-size.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
|
||||
$(TM_H) $(TREE_H) $(DIAGNOSTIC_H) $(TREE_FLOW_H) tree-pass.h \
|
||||
tree-ssa-propagate.h
|
||||
tree-gimple.o : tree-gimple.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(EXPR_H) \
|
||||
$(RTL_H) $(TREE_GIMPLE_H) $(TM_H) coretypes.h bitmap.h $(GGC_H) \
|
||||
output.h $(TREE_FLOW_H)
|
||||
|
|
|
@ -55,6 +55,8 @@ DEF_ATTR_FOR_INT (1)
|
|||
DEF_ATTR_FOR_INT (2)
|
||||
DEF_ATTR_FOR_INT (3)
|
||||
DEF_ATTR_FOR_INT (4)
|
||||
DEF_ATTR_FOR_INT (5)
|
||||
DEF_ATTR_FOR_INT (6)
|
||||
#undef DEF_ATTR_FOR_INT
|
||||
|
||||
/* Construct a tree for a list of two integers. */
|
||||
|
@ -67,6 +69,10 @@ DEF_LIST_INT_INT (2,0)
|
|||
DEF_LIST_INT_INT (2,3)
|
||||
DEF_LIST_INT_INT (3,0)
|
||||
DEF_LIST_INT_INT (3,4)
|
||||
DEF_LIST_INT_INT (4,0)
|
||||
DEF_LIST_INT_INT (4,5)
|
||||
DEF_LIST_INT_INT (5,0)
|
||||
DEF_LIST_INT_INT (5,6)
|
||||
#undef DEF_LIST_INT_INT
|
||||
|
||||
/* Construct trees for identifiers. */
|
||||
|
@ -127,6 +133,12 @@ DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_2, ATTR_NONNULL, ATTR_LIST_2, \
|
|||
/* Nothrow functions whose third parameter is a nonnull pointer. */
|
||||
DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_3, ATTR_NONNULL, ATTR_LIST_3, \
|
||||
ATTR_NOTHROW_LIST)
|
||||
/* Nothrow functions whose fourth parameter is a nonnull pointer. */
|
||||
DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_4, ATTR_NONNULL, ATTR_LIST_4, \
|
||||
ATTR_NOTHROW_LIST)
|
||||
/* Nothrow functions whose fifth parameter is a nonnull pointer. */
|
||||
DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_5, ATTR_NONNULL, ATTR_LIST_5, \
|
||||
ATTR_NOTHROW_LIST)
|
||||
/* Nothrow const functions whose pointer parameter(s) are all nonnull. */
|
||||
DEF_ATTR_TREE_LIST (ATTR_CONST_NOTHROW_NONNULL, ATTR_CONST, ATTR_NULL, \
|
||||
ATTR_NOTHROW_NONNULL)
|
||||
|
@ -149,6 +161,10 @@ DEF_FORMAT_ATTRIBUTE(PRINTF,2,2_0)
|
|||
DEF_FORMAT_ATTRIBUTE(PRINTF,2,2_3)
|
||||
DEF_FORMAT_ATTRIBUTE(PRINTF,3,3_0)
|
||||
DEF_FORMAT_ATTRIBUTE(PRINTF,3,3_4)
|
||||
DEF_FORMAT_ATTRIBUTE(PRINTF,4,4_0)
|
||||
DEF_FORMAT_ATTRIBUTE(PRINTF,4,4_5)
|
||||
DEF_FORMAT_ATTRIBUTE(PRINTF,5,5_0)
|
||||
DEF_FORMAT_ATTRIBUTE(PRINTF,5,5_6)
|
||||
DEF_FORMAT_ATTRIBUTE(SCANF,1,1_0)
|
||||
DEF_FORMAT_ATTRIBUTE(SCANF,1,1_2)
|
||||
DEF_FORMAT_ATTRIBUTE(SCANF,2,2_0)
|
||||
|
|
|
@ -32,6 +32,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
|
|||
DEF_FUNCTION_TYPE_2 (ENUM, RETURN, ARG1, ARG2)
|
||||
DEF_FUNCTION_TYPE_3 (ENUM, RETURN, ARG1, ARG2, ARG3)
|
||||
DEF_FUNCTION_TYPE_4 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4)
|
||||
DEF_FUNCTION_TYPE_5 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5)
|
||||
|
||||
These macros describe function types. ENUM is as above. The
|
||||
RETURN type is one of the enumerals already defined. ARG1, ARG2,
|
||||
|
@ -41,6 +42,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
|
|||
DEF_FUNCTION_TYPE_VAR_1 (ENUM, RETURN, ARG1)
|
||||
DEF_FUNCTION_TYPE_VAR_2 (ENUM, RETURN, ARG1, ARG2)
|
||||
DEF_FUNCTION_TYPE_VAR_3 (ENUM, RETURN, ARG1, ARG2, ARG3)
|
||||
DEF_FUNCTION_TYPE_VAR_4 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4)
|
||||
|
||||
Similar, but for function types that take variable arguments.
|
||||
For example:
|
||||
|
@ -252,6 +254,7 @@ DEF_FUNCTION_TYPE_2 (BT_FN_COMPLEX_LONGDOUBLE_COMPLEX_LONGDOUBLE_COMPLEX_LONGDOU
|
|||
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTR_PTR, BT_VOID, BT_PTR, BT_PTR)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_INT_CONST_STRING_PTR_CONST_STRING,
|
||||
BT_INT, BT_CONST_STRING, BT_PTR_CONST_STRING)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_SIZE_CONST_PTR_INT, BT_SIZE, BT_CONST_PTR, BT_INT)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_I1_VPTR_I1, BT_I1, BT_VOLATILE_PTR, BT_I1)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_I2_VPTR_I2, BT_I2, BT_VOLATILE_PTR, BT_I2)
|
||||
DEF_FUNCTION_TYPE_2 (BT_FN_I4_VPTR_I4, BT_I4, BT_VOLATILE_PTR, BT_I4)
|
||||
|
@ -300,6 +303,8 @@ DEF_FUNCTION_TYPE_3 (BT_FN_VOID_LONGDOUBLE_LONGDOUBLEPTR_LONGDOUBLEPTR,
|
|||
DEF_FUNCTION_TYPE_3 (BT_FN_VOID_PTR_PTR_PTR, BT_VOID, BT_PTR, BT_PTR, BT_PTR)
|
||||
DEF_FUNCTION_TYPE_3 (BT_FN_INT_CONST_STRING_PTR_CONST_STRING_PTR_CONST_STRING,
|
||||
BT_INT, BT_CONST_STRING, BT_PTR_CONST_STRING, BT_PTR_CONST_STRING)
|
||||
DEF_FUNCTION_TYPE_3 (BT_FN_INT_INT_CONST_STRING_VALIST_ARG,
|
||||
BT_INT, BT_INT, BT_CONST_STRING, BT_VALIST_ARG)
|
||||
DEF_FUNCTION_TYPE_3 (BT_FN_BOOL_VPTR_I1_I1, BT_BOOL, BT_VOLATILE_PTR,
|
||||
BT_I1, BT_I1)
|
||||
DEF_FUNCTION_TYPE_3 (BT_FN_BOOL_VPTR_I2_I2, BT_BOOL, BT_VOLATILE_PTR,
|
||||
|
@ -319,6 +324,22 @@ DEF_FUNCTION_TYPE_4 (BT_FN_INT_STRING_SIZE_CONST_STRING_VALIST_ARG,
|
|||
BT_INT, BT_STRING, BT_SIZE, BT_CONST_STRING, BT_VALIST_ARG)
|
||||
DEF_FUNCTION_TYPE_4 (BT_FN_SIZE_STRING_SIZE_CONST_STRING_CONST_PTR,
|
||||
BT_SIZE, BT_STRING, BT_SIZE, BT_CONST_STRING, BT_CONST_PTR)
|
||||
DEF_FUNCTION_TYPE_4 (BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE,
|
||||
BT_PTR, BT_PTR, BT_CONST_PTR, BT_SIZE, BT_SIZE)
|
||||
DEF_FUNCTION_TYPE_4 (BT_FN_PTR_PTR_INT_SIZE_SIZE,
|
||||
BT_PTR, BT_PTR, BT_INT, BT_SIZE, BT_SIZE)
|
||||
DEF_FUNCTION_TYPE_4 (BT_FN_STRING_STRING_CONST_STRING_SIZE_SIZE,
|
||||
BT_STRING, BT_STRING, BT_CONST_STRING, BT_SIZE, BT_SIZE)
|
||||
DEF_FUNCTION_TYPE_4 (BT_FN_INT_FILEPTR_INT_CONST_STRING_VALIST_ARG,
|
||||
BT_INT, BT_FILEPTR, BT_INT, BT_CONST_STRING, BT_VALIST_ARG)
|
||||
|
||||
DEF_FUNCTION_TYPE_5 (BT_FN_INT_STRING_INT_SIZE_CONST_STRING_VALIST_ARG,
|
||||
BT_INT, BT_STRING, BT_INT, BT_SIZE, BT_CONST_STRING,
|
||||
BT_VALIST_ARG)
|
||||
|
||||
DEF_FUNCTION_TYPE_6 (BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VALIST_ARG,
|
||||
BT_INT, BT_STRING, BT_SIZE, BT_INT, BT_SIZE,
|
||||
BT_CONST_STRING, BT_VALIST_ARG)
|
||||
|
||||
DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID)
|
||||
DEF_FUNCTION_TYPE_VAR_0 (BT_FN_INT_VAR, BT_INT)
|
||||
|
@ -337,11 +358,22 @@ DEF_FUNCTION_TYPE_VAR_2 (BT_FN_INT_STRING_CONST_STRING_VAR,
|
|||
BT_INT, BT_STRING, BT_CONST_STRING)
|
||||
DEF_FUNCTION_TYPE_VAR_2 (BT_FN_INT_CONST_STRING_CONST_STRING_VAR,
|
||||
BT_INT, BT_CONST_STRING, BT_CONST_STRING)
|
||||
DEF_FUNCTION_TYPE_VAR_2 (BT_FN_INT_INT_CONST_STRING_VAR,
|
||||
BT_INT, BT_INT, BT_CONST_STRING)
|
||||
|
||||
DEF_FUNCTION_TYPE_VAR_3 (BT_FN_INT_STRING_SIZE_CONST_STRING_VAR,
|
||||
BT_INT, BT_STRING, BT_SIZE, BT_CONST_STRING)
|
||||
DEF_FUNCTION_TYPE_VAR_3 (BT_FN_SSIZE_STRING_SIZE_CONST_STRING_VAR,
|
||||
BT_SSIZE, BT_STRING, BT_SIZE, BT_CONST_STRING)
|
||||
DEF_FUNCTION_TYPE_VAR_3 (BT_FN_INT_FILEPTR_INT_CONST_STRING_VAR,
|
||||
BT_INT, BT_FILEPTR, BT_INT, BT_CONST_STRING)
|
||||
|
||||
DEF_FUNCTION_TYPE_VAR_4 (BT_FN_INT_STRING_INT_SIZE_CONST_STRING_VAR,
|
||||
BT_INT, BT_STRING, BT_INT, BT_SIZE, BT_CONST_STRING)
|
||||
|
||||
DEF_FUNCTION_TYPE_VAR_5 (BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VAR,
|
||||
BT_INT, BT_STRING, BT_SIZE, BT_INT, BT_SIZE,
|
||||
BT_CONST_STRING)
|
||||
|
||||
DEF_POINTER_TYPE (BT_PTR_FN_VOID_VAR, BT_FN_VOID_VAR)
|
||||
DEF_FUNCTION_TYPE_3 (BT_FN_PTR_PTR_FN_VOID_VAR_PTR_SIZE,
|
||||
|
|
1225
gcc/builtins.c
1225
gcc/builtins.c
File diff suppressed because it is too large
Load diff
|
@ -658,6 +658,26 @@ DEF_BUILTIN_STUB (BUILT_IN_NONLOCAL_GOTO, "__builtin_nonlocal_goto")
|
|||
DEF_BUILTIN_STUB (BUILT_IN_STACK_SAVE, "__builtin_stack_save")
|
||||
DEF_BUILTIN_STUB (BUILT_IN_STACK_RESTORE, "__builtin_stack_restore")
|
||||
|
||||
/* Object size checking builtins. */
|
||||
DEF_GCC_BUILTIN (BUILT_IN_OBJECT_SIZE, "object_size", BT_FN_SIZE_CONST_PTR_INT, ATTR_PURE_NOTHROW_LIST)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMCPY_CHK, "__memcpy_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_NOTHROW_NONNULL)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMMOVE_CHK, "__memmove_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_NOTHROW_NONNULL)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMPCPY_CHK, "__mempcpy_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_NOTHROW_NONNULL)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMSET_CHK, "__memset_chk", BT_FN_PTR_PTR_INT_SIZE_SIZE, ATTR_NOTHROW_NONNULL)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STPCPY_CHK, "__stpcpy_chk", BT_FN_STRING_STRING_CONST_STRING_SIZE, ATTR_NOTHROW_NONNULL)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRCAT_CHK, "__strcat_chk", BT_FN_STRING_STRING_CONST_STRING_SIZE, ATTR_NOTHROW_NONNULL)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRCPY_CHK, "__strcpy_chk", BT_FN_STRING_STRING_CONST_STRING_SIZE, ATTR_NOTHROW_NONNULL)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRNCAT_CHK, "__strncat_chk", BT_FN_STRING_STRING_CONST_STRING_SIZE_SIZE, ATTR_NOTHROW_NONNULL)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRNCPY_CHK, "__strncpy_chk", BT_FN_STRING_STRING_CONST_STRING_SIZE_SIZE, ATTR_NOTHROW_NONNULL)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_SNPRINTF_CHK, "__snprintf_chk", BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VAR, ATTR_FORMAT_PRINTF_5_6)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_SPRINTF_CHK, "__sprintf_chk", BT_FN_INT_STRING_INT_SIZE_CONST_STRING_VAR, ATTR_FORMAT_PRINTF_4_5)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_VSNPRINTF_CHK, "__vsnprintf_chk", BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VALIST_ARG, ATTR_FORMAT_PRINTF_5_0)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_VSPRINTF_CHK, "__vsprintf_chk", BT_FN_INT_STRING_INT_SIZE_CONST_STRING_VALIST_ARG, ATTR_FORMAT_PRINTF_4_0)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_FPRINTF_CHK, "__fprintf_chk", BT_FN_INT_FILEPTR_INT_CONST_STRING_VAR, ATTR_FORMAT_PRINTF_3_4)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_PRINTF_CHK, "__printf_chk", BT_FN_INT_INT_CONST_STRING_VAR, ATTR_FORMAT_PRINTF_2_3)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_VFPRINTF_CHK, "__vfprintf_chk", BT_FN_INT_FILEPTR_INT_CONST_STRING_VALIST_ARG, ATTR_FORMAT_PRINTF_3_0)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_VPRINTF_CHK, "__vprintf_chk", BT_FN_INT_INT_CONST_STRING_VALIST_ARG, ATTR_FORMAT_PRINTF_2_0)
|
||||
|
||||
/* Profiling hooks. */
|
||||
DEF_BUILTIN_STUB (BUILT_IN_PROFILE_FUNC_ENTER, "profile_func_enter")
|
||||
DEF_BUILTIN_STUB (BUILT_IN_PROFILE_FUNC_EXIT, "profile_func_exit")
|
||||
|
|
|
@ -2924,10 +2924,16 @@ c_common_nodes_and_builtins (void)
|
|||
#define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME,
|
||||
#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
|
||||
#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
|
||||
#define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME,
|
||||
#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) \
|
||||
NAME,
|
||||
#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
|
||||
#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
|
||||
#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
|
||||
#define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
|
||||
#define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
|
||||
#define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG6) \
|
||||
NAME,
|
||||
#define DEF_POINTER_TYPE(NAME, TYPE) NAME,
|
||||
#include "builtin-types.def"
|
||||
#undef DEF_PRIMITIVE_TYPE
|
||||
|
@ -2936,10 +2942,14 @@ c_common_nodes_and_builtins (void)
|
|||
#undef DEF_FUNCTION_TYPE_2
|
||||
#undef DEF_FUNCTION_TYPE_3
|
||||
#undef DEF_FUNCTION_TYPE_4
|
||||
#undef DEF_FUNCTION_TYPE_5
|
||||
#undef DEF_FUNCTION_TYPE_6
|
||||
#undef DEF_FUNCTION_TYPE_VAR_0
|
||||
#undef DEF_FUNCTION_TYPE_VAR_1
|
||||
#undef DEF_FUNCTION_TYPE_VAR_2
|
||||
#undef DEF_FUNCTION_TYPE_VAR_3
|
||||
#undef DEF_FUNCTION_TYPE_VAR_4
|
||||
#undef DEF_FUNCTION_TYPE_VAR_5
|
||||
#undef DEF_POINTER_TYPE
|
||||
BT_LAST
|
||||
};
|
||||
|
@ -3188,6 +3198,42 @@ c_common_nodes_and_builtins (void)
|
|||
tree_cons (NULL_TREE, \
|
||||
builtin_types[(int) ARG4], \
|
||||
void_list_node)))));
|
||||
#define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
|
||||
builtin_types[(int) ENUM] \
|
||||
= build_function_type \
|
||||
(builtin_types[(int) RETURN], \
|
||||
tree_cons (NULL_TREE, \
|
||||
builtin_types[(int) ARG1], \
|
||||
tree_cons (NULL_TREE, \
|
||||
builtin_types[(int) ARG2], \
|
||||
tree_cons \
|
||||
(NULL_TREE, \
|
||||
builtin_types[(int) ARG3], \
|
||||
tree_cons (NULL_TREE, \
|
||||
builtin_types[(int) ARG4], \
|
||||
tree_cons (NULL_TREE, \
|
||||
builtin_types[(int) ARG5],\
|
||||
void_list_node))))));
|
||||
#define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
||||
ARG6) \
|
||||
builtin_types[(int) ENUM] \
|
||||
= build_function_type \
|
||||
(builtin_types[(int) RETURN], \
|
||||
tree_cons (NULL_TREE, \
|
||||
builtin_types[(int) ARG1], \
|
||||
tree_cons (NULL_TREE, \
|
||||
builtin_types[(int) ARG2], \
|
||||
tree_cons \
|
||||
(NULL_TREE, \
|
||||
builtin_types[(int) ARG3], \
|
||||
tree_cons \
|
||||
(NULL_TREE, \
|
||||
builtin_types[(int) ARG4], \
|
||||
tree_cons (NULL_TREE, \
|
||||
builtin_types[(int) ARG5], \
|
||||
tree_cons (NULL_TREE, \
|
||||
builtin_types[(int) ARG6],\
|
||||
void_list_node)))))));
|
||||
#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
|
||||
builtin_types[(int) ENUM] \
|
||||
= build_function_type (builtin_types[(int) RETURN], NULL_TREE);
|
||||
|
@ -3220,6 +3266,38 @@ c_common_nodes_and_builtins (void)
|
|||
builtin_types[(int) ARG3], \
|
||||
NULL_TREE))));
|
||||
|
||||
#define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
|
||||
builtin_types[(int) ENUM] \
|
||||
= build_function_type \
|
||||
(builtin_types[(int) RETURN], \
|
||||
tree_cons (NULL_TREE, \
|
||||
builtin_types[(int) ARG1], \
|
||||
tree_cons (NULL_TREE, \
|
||||
builtin_types[(int) ARG2], \
|
||||
tree_cons (NULL_TREE, \
|
||||
builtin_types[(int) ARG3], \
|
||||
tree_cons (NULL_TREE, \
|
||||
builtin_types[(int) ARG4],\
|
||||
NULL_TREE)))));
|
||||
|
||||
#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, \
|
||||
ARG5) \
|
||||
builtin_types[(int) ENUM] \
|
||||
= build_function_type \
|
||||
(builtin_types[(int) RETURN], \
|
||||
tree_cons (NULL_TREE, \
|
||||
builtin_types[(int) ARG1], \
|
||||
tree_cons (NULL_TREE, \
|
||||
builtin_types[(int) ARG2], \
|
||||
tree_cons \
|
||||
(NULL_TREE, \
|
||||
builtin_types[(int) ARG3], \
|
||||
tree_cons (NULL_TREE, \
|
||||
builtin_types[(int) ARG4], \
|
||||
tree_cons (NULL_TREE, \
|
||||
builtin_types[(int) ARG5],\
|
||||
NULL_TREE))))));
|
||||
|
||||
#define DEF_POINTER_TYPE(ENUM, TYPE) \
|
||||
builtin_types[(int) ENUM] \
|
||||
= build_pointer_type (builtin_types[(int) TYPE]);
|
||||
|
@ -3229,10 +3307,14 @@ c_common_nodes_and_builtins (void)
|
|||
#undef DEF_FUNCTION_TYPE_2
|
||||
#undef DEF_FUNCTION_TYPE_3
|
||||
#undef DEF_FUNCTION_TYPE_4
|
||||
#undef DEF_FUNCTION_TYPE_5
|
||||
#undef DEF_FUNCTION_TYPE_6
|
||||
#undef DEF_FUNCTION_TYPE_VAR_0
|
||||
#undef DEF_FUNCTION_TYPE_VAR_1
|
||||
#undef DEF_FUNCTION_TYPE_VAR_2
|
||||
#undef DEF_FUNCTION_TYPE_VAR_3
|
||||
#undef DEF_FUNCTION_TYPE_VAR_4
|
||||
#undef DEF_FUNCTION_TYPE_VAR_5
|
||||
#undef DEF_POINTER_TYPE
|
||||
|
||||
c_init_attributes ();
|
||||
|
|
|
@ -71,6 +71,8 @@ extensions, accepted by GCC in C89 mode and in C++.
|
|||
* Vector Extensions:: Using vector instructions through built-in functions.
|
||||
* Offsetof:: Special syntax for implementing @code{offsetof}.
|
||||
* Atomic Builtins:: Built-in functions for atomic memory access.
|
||||
* Object Size Checking:: Built-in functions for limited buffer overflow
|
||||
checking.
|
||||
* Other Builtins:: Other built-in functions.
|
||||
* Target Builtins:: Built-in functions specific to particular targets.
|
||||
* Target Format Checks:: Format checks specific to particular targets.
|
||||
|
@ -4724,6 +4726,139 @@ previous memory loads have been satisfied, but following memory reads
|
|||
are not prevented from being speculated to before the barrier.
|
||||
@end table
|
||||
|
||||
@node Object Size Checking
|
||||
@section Object Size Checking Builtins
|
||||
@findex __builtin_object_size
|
||||
@findex __builtin___memcpy_chk
|
||||
@findex __builtin___mempcpy_chk
|
||||
@findex __builtin___memmove_chk
|
||||
@findex __builtin___memset_chk
|
||||
@findex __builtin___strcpy_chk
|
||||
@findex __builtin___stpcpy_chk
|
||||
@findex __builtin___strncpy_chk
|
||||
@findex __builtin___strcat_chk
|
||||
@findex __builtin___strncat_chk
|
||||
@findex __builtin___sprintf_chk
|
||||
@findex __builtin___snprintf_chk
|
||||
@findex __builtin___vsprintf_chk
|
||||
@findex __builtin___vsnprintf_chk
|
||||
@findex __builtin___printf_chk
|
||||
@findex __builtin___vprintf_chk
|
||||
@findex __builtin___fprintf_chk
|
||||
@findex __builtin___vfprintf_chk
|
||||
|
||||
GCC implements a limited buffer overflow protection mechanism
|
||||
that can prevent some buffer overflow attacks.
|
||||
|
||||
@deftypefn {Built-in Function} {size_t} __builtin_object_size (void * @var{ptr}, int @var{type})
|
||||
is a built-in construct that returns a constant number of bytes from
|
||||
@var{ptr} to the end of the object @var{ptr} pointer points to
|
||||
(if known at compile time). @code{__builtin_object_size} never evaluates
|
||||
its arguments for side-effects. If there are any side-effects in them, it
|
||||
returns @code{(size_t) -1} for @var{type} 0 or 1 and @code{(size_t) 0}
|
||||
for @var{type} 2 or 3. If there are multiple objects @var{ptr} can
|
||||
point to and all of them are known at compile time, the returned number
|
||||
is the maximum of remaining byte counts in those objects if @var{type} & 2 is
|
||||
0 and minimum if non-zero. If it is not possible to determine which objects
|
||||
@var{ptr} points to at compile time, @code{__builtin_object_size} should
|
||||
return @code{(size_t) -1} for @var{type} 0 or 1 and @code{(size_t) 0}
|
||||
for @var{type} 2 or 3.
|
||||
|
||||
@var{type} is an integer constant from 0 to 3. If the least significant
|
||||
bit is clear, objects are whole variables, if it is set, a closest
|
||||
surrounding subobject is considered the object a pointer points to.
|
||||
The second bit determines if maximum or minimum of remaining bytes
|
||||
is computed.
|
||||
|
||||
@smallexample
|
||||
struct V @{ char buf1[10]; int b; char buf2[10]; @} var;
|
||||
char *p = &var.buf1[1], *q = &var.b;
|
||||
|
||||
/* Here the object p points to is var. */
|
||||
assert (__builtin_object_size (p, 0) == sizeof (var) - 1);
|
||||
/* The subobject p points to is var.buf1. */
|
||||
assert (__builtin_object_size (p, 1) == sizeof (var.buf1) - 1);
|
||||
/* The object q points to is var. */
|
||||
assert (__builtin_object_size (q, 0)
|
||||
== (char *) (&var + 1) - (char *) &var.b);
|
||||
/* The subobject q points to is var.b. */
|
||||
assert (__builtin_object_size (q, 1) == sizeof (var.b));
|
||||
@end smallexample
|
||||
@end deftypefn
|
||||
|
||||
There are built-in functions added for many common string operation
|
||||
functions, e.g. for @code{memcpy} @code{__builtin___memcpy_chk}
|
||||
built-in is provided. This built-in has an additional last argument,
|
||||
which is the number of bytes remaining in object the @var{dest}
|
||||
argument points to or @code{(size_t) -1} if the size is not known.
|
||||
|
||||
The built-in functions are optimized into the normal string functions
|
||||
like @code{memcpy} if the last argument is @code{(size_t) -1} or if
|
||||
it is known at compile time that the destination object will not
|
||||
be overflown. If the compiler can determine at compile time the
|
||||
object will be always overflown, it issues a warning.
|
||||
|
||||
The intended use can be e.g.
|
||||
|
||||
@smallexample
|
||||
#undef memcpy
|
||||
#define bos0(dest) __builtin_object_size (dest, 0)
|
||||
#define memcpy(dest, src, n) \
|
||||
__builtin___memcpy_chk (dest, src, n, bos0 (dest))
|
||||
|
||||
char *volatile p;
|
||||
char buf[10];
|
||||
/* It is unknown what object p points to, so this is optimized
|
||||
into plain memcpy - no checking is possible. */
|
||||
memcpy (p, "abcde", n);
|
||||
/* Destination is known and length too. It is known at compile
|
||||
time there will be no overflow. */
|
||||
memcpy (&buf[5], "abcde", 5);
|
||||
/* Destination is known, but the length is not known at compile time.
|
||||
This will result in __memcpy_chk call that can check for overflow
|
||||
at runtime. */
|
||||
memcpy (&buf[5], "abcde", n);
|
||||
/* Destination is known and it is known at compile time there will
|
||||
be overflow. There will be a warning and __memcpy_chk call that
|
||||
will abort the program at runtime. */
|
||||
memcpy (&buf[6], "abcde", 5);
|
||||
@end smallexample
|
||||
|
||||
Such built-in functions are provided for @code{memcpy}, @code{mempcpy},
|
||||
@code{memmove}, @code{memset}, @code{strcpy}, @code{stpcpy}, @code{strncpy},
|
||||
@code{strcat} and @code{strncat}.
|
||||
|
||||
There are also checking built-in functions for formatted output functions.
|
||||
@smallexample
|
||||
int __builtin___sprintf_chk (char *s, int flag, size_t os, const char *fmt, ...);
|
||||
int __builtin___snprintf_chk (char *s, size_t maxlen, int flag, size_t os,
|
||||
const char *fmt, ...);
|
||||
int __builtin___vsprintf_chk (char *s, int flag, size_t os, const char *fmt,
|
||||
va_list ap);
|
||||
int __builtin___vsnprintf_chk (char *s, size_t maxlen, int flag, size_t os,
|
||||
const char *fmt, va_list ap);
|
||||
@end smallexample
|
||||
|
||||
The added @var{flag} argument is passed unchanged to @code{__sprintf_chk}
|
||||
etc. functions and can contain implementation specific flags on what
|
||||
additional security measures the checking function might take, such as
|
||||
handling @code{%n} differently.
|
||||
|
||||
The @var{os} argument is the object size @var{s} points to, like in the
|
||||
other built-in functions. There is a small difference in the behaviour
|
||||
though, if @var{os} is @code{(size_t) -1}, the built-in functions are
|
||||
optimized into the non-checking functions only if @var{flag} is 0, otherwise
|
||||
the checking function is called with @var{os} argument set to
|
||||
@code{(size_t) -1}.
|
||||
|
||||
In addition to this, there are checking built-in functions
|
||||
@code{__builtin___printf_chk}, @code{__builtin___vprintf_chk},
|
||||
@code{__builtin___fprintf_chk} and @code{__builtin___vfprintf_chk}.
|
||||
These have just one additional argument, @var{flag}, right before
|
||||
format string @var{fmt}. If the compiler is able to optimize them to
|
||||
@code{fputc} etc. functions, it will, otherwise the checking function
|
||||
should be called and the @var{flag} argument passed to it.
|
||||
|
||||
@node Other Builtins
|
||||
@section Other built-in functions provided by GCC
|
||||
@cindex built-in functions
|
||||
|
|
|
@ -1,3 +1,61 @@
|
|||
2005-06-27 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* 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.
|
||||
|
||||
2005-06-27 Michael Matz <matz@suse.de>
|
||||
|
||||
* gcc.target/x86_64/abi/test_struct_returning.c: Adjust as return
|
||||
|
|
81
gcc/testsuite/gcc.c-torture/execute/builtins/chk.h
Normal file
81
gcc/testsuite/gcc.c-torture/execute/builtins/chk.h
Normal file
|
@ -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;
|
472
gcc/testsuite/gcc.c-torture/execute/builtins/lib/chk.c
Normal file
472
gcc/testsuite/gcc.c-torture/execute/builtins/lib/chk.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
extern void abort(void);
|
||||
extern void main_test (void);
|
||||
extern void abort (void);
|
||||
int inside_main;
|
||||
|
||||
int
|
||||
|
|
|
@ -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--;
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
#include "lib/chk.c"
|
479
gcc/testsuite/gcc.c-torture/execute/builtins/memcpy-chk.c
Normal file
479
gcc/testsuite/gcc.c-torture/execute/builtins/memcpy-chk.c
Normal file
|
@ -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 ();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include "lib/chk.c"
|
579
gcc/testsuite/gcc.c-torture/execute/builtins/memmove-chk.c
Normal file
579
gcc/testsuite/gcc.c-torture/execute/builtins/memmove-chk.c
Normal file
|
@ -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 ();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include "lib/chk.c"
|
487
gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-chk.c
Normal file
487
gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy-chk.c
Normal file
|
@ -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 ();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include "lib/chk.c"
|
721
gcc/testsuite/gcc.c-torture/execute/builtins/memset-chk.c
Normal file
721
gcc/testsuite/gcc.c-torture/execute/builtins/memset-chk.c
Normal file
|
@ -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 ();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include "lib/chk.c"
|
220
gcc/testsuite/gcc.c-torture/execute/builtins/snprintf-chk.c
Normal file
220
gcc/testsuite/gcc.c-torture/execute/builtins/snprintf-chk.c
Normal file
|
@ -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 ();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include "lib/chk.c"
|
197
gcc/testsuite/gcc.c-torture/execute/builtins/sprintf-chk.c
Normal file
197
gcc/testsuite/gcc.c-torture/execute/builtins/sprintf-chk.c
Normal file
|
@ -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 ();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include "lib/chk.c"
|
265
gcc/testsuite/gcc.c-torture/execute/builtins/stpcpy-chk.c
Normal file
265
gcc/testsuite/gcc.c-torture/execute/builtins/stpcpy-chk.c
Normal file
|
@ -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 ();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include "lib/chk.c"
|
204
gcc/testsuite/gcc.c-torture/execute/builtins/strcat-chk.c
Normal file
204
gcc/testsuite/gcc.c-torture/execute/builtins/strcat-chk.c
Normal file
|
@ -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 ();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include "lib/chk.c"
|
234
gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-chk.c
Normal file
234
gcc/testsuite/gcc.c-torture/execute/builtins/strcpy-chk.c
Normal file
|
@ -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 ();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include "lib/chk.c"
|
229
gcc/testsuite/gcc.c-torture/execute/builtins/strncat-chk.c
Normal file
229
gcc/testsuite/gcc.c-torture/execute/builtins/strncat-chk.c
Normal file
|
@ -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 ();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include "lib/chk.c"
|
227
gcc/testsuite/gcc.c-torture/execute/builtins/strncpy-chk.c
Normal file
227
gcc/testsuite/gcc.c-torture/execute/builtins/strncpy-chk.c
Normal file
|
@ -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 ();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include "lib/chk.c"
|
321
gcc/testsuite/gcc.c-torture/execute/builtins/vsnprintf-chk.c
Normal file
321
gcc/testsuite/gcc.c-torture/execute/builtins/vsnprintf-chk.c
Normal file
|
@ -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 ();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include "lib/chk.c"
|
290
gcc/testsuite/gcc.c-torture/execute/builtins/vsprintf-chk.c
Normal file
290
gcc/testsuite/gcc.c-torture/execute/builtins/vsprintf-chk.c
Normal file
|
@ -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 ();
|
||||
}
|
23
gcc/testsuite/gcc.c-torture/execute/fprintf-1.c
Normal file
23
gcc/testsuite/gcc.c-torture/execute/fprintf-1.c
Normal file
|
@ -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;
|
||||
}
|
49
gcc/testsuite/gcc.c-torture/execute/fprintf-chk-1.c
Normal file
49
gcc/testsuite/gcc.c-torture/execute/fprintf-chk-1.c
Normal file
|
@ -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;
|
||||
}
|
23
gcc/testsuite/gcc.c-torture/execute/printf-1.c
Normal file
23
gcc/testsuite/gcc.c-torture/execute/printf-1.c
Normal file
|
@ -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;
|
||||
}
|
49
gcc/testsuite/gcc.c-torture/execute/printf-chk-1.c
Normal file
49
gcc/testsuite/gcc.c-torture/execute/printf-chk-1.c
Normal file
|
@ -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;
|
||||
}
|
53
gcc/testsuite/gcc.c-torture/execute/vfprintf-1.c
Normal file
53
gcc/testsuite/gcc.c-torture/execute/vfprintf-1.c
Normal file
|
@ -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
|
73
gcc/testsuite/gcc.c-torture/execute/vfprintf-chk-1.c
Normal file
73
gcc/testsuite/gcc.c-torture/execute/vfprintf-chk-1.c
Normal file
|
@ -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
|
53
gcc/testsuite/gcc.c-torture/execute/vprintf-1.c
Normal file
53
gcc/testsuite/gcc.c-torture/execute/vprintf-1.c
Normal file
|
@ -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
|
73
gcc/testsuite/gcc.c-torture/execute/vprintf-chk-1.c
Normal file
73
gcc/testsuite/gcc.c-torture/execute/vprintf-chk-1.c
Normal file
|
@ -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
|
436
gcc/testsuite/gcc.dg/builtin-object-size-1.c
Normal file
436
gcc/testsuite/gcc.dg/builtin-object-size-1.c
Normal file
|
@ -0,0 +1,436 @@
|
|||
/* { dg-do run } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
extern void abort (void);
|
||||
extern void exit (int);
|
||||
extern void *malloc (size_t);
|
||||
extern void *calloc (size_t, size_t);
|
||||
extern void *alloca (size_t);
|
||||
extern void *memcpy (void *, const void *, size_t);
|
||||
extern void *memset (void *, int, size_t);
|
||||
extern char *strcpy (char *, const char *);
|
||||
|
||||
struct A
|
||||
{
|
||||
char a[10];
|
||||
int b;
|
||||
char c[10];
|
||||
} y, w[4];
|
||||
|
||||
extern char exta[];
|
||||
extern char extb[30];
|
||||
extern struct A zerol[0];
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test1 (void *q, int x)
|
||||
{
|
||||
struct A a;
|
||||
void *p = &a.a[3], *r;
|
||||
char var[x + 10];
|
||||
if (x < 0)
|
||||
r = &a.a[9];
|
||||
else
|
||||
r = &a.c[1];
|
||||
if (__builtin_object_size (p, 0)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, a) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&a.c[9], 0)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, c) - 9)
|
||||
abort ();
|
||||
if (__builtin_object_size (q, 0) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (r, 0)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, a) - 9)
|
||||
abort ();
|
||||
if (x < 6)
|
||||
r = &w[2].a[1];
|
||||
else
|
||||
r = &a.a[6];
|
||||
if (__builtin_object_size (&y, 0)
|
||||
!= sizeof (y))
|
||||
abort ();
|
||||
if (__builtin_object_size (w, 0)
|
||||
!= sizeof (w))
|
||||
abort ();
|
||||
if (__builtin_object_size (&y.b, 0)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, b))
|
||||
abort ();
|
||||
if (__builtin_object_size (r, 0)
|
||||
!= 2 * sizeof (w[0]) - __builtin_offsetof (struct A, a) - 1)
|
||||
abort ();
|
||||
if (x < 20)
|
||||
r = malloc (30);
|
||||
else
|
||||
r = calloc (2, 16);
|
||||
if (__builtin_object_size (r, 0) != 2 * 16)
|
||||
abort ();
|
||||
if (x < 20)
|
||||
r = malloc (30);
|
||||
else
|
||||
r = calloc (2, 14);
|
||||
if (__builtin_object_size (r, 0) != 30)
|
||||
abort ();
|
||||
if (x < 30)
|
||||
r = malloc (sizeof (a));
|
||||
else
|
||||
r = &a.a[3];
|
||||
if (__builtin_object_size (r, 0) != sizeof (a))
|
||||
abort ();
|
||||
r = memcpy (r, "a", 2);
|
||||
if (__builtin_object_size (r, 0) != sizeof (a))
|
||||
abort ();
|
||||
r = memcpy (r + 2, "b", 2) + 2;
|
||||
if (__builtin_object_size (r, 0) != sizeof (a) - 4)
|
||||
abort ();
|
||||
r = &a.a[4];
|
||||
r = memset (r, 'a', 2);
|
||||
if (__builtin_object_size (r, 0)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, a) - 4)
|
||||
abort ();
|
||||
r = memset (r + 2, 'b', 2) + 2;
|
||||
if (__builtin_object_size (r, 0)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, a) - 8)
|
||||
abort ();
|
||||
r = &a.a[1];
|
||||
r = strcpy (r, "ab");
|
||||
if (__builtin_object_size (r, 0)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, a) - 1)
|
||||
abort ();
|
||||
r = strcpy (r + 2, "cd") + 2;
|
||||
if (__builtin_object_size (r, 0)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, a) - 5)
|
||||
abort ();
|
||||
if (__builtin_object_size (exta, 0) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (exta + 10, 0) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&exta[5], 0) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (extb, 0) != sizeof (extb))
|
||||
abort ();
|
||||
if (__builtin_object_size (extb + 10, 0) != sizeof (extb) - 10)
|
||||
abort ();
|
||||
if (__builtin_object_size (&extb[5], 0) != sizeof (extb) - 5)
|
||||
abort ();
|
||||
if (__builtin_object_size (var, 0) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (var + 10, 0) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&var[5], 0) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (zerol, 0) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&zerol, 0) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&zerol[0], 0) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (zerol[0].a, 0) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&zerol[0].a[0], 0) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&zerol[0].b, 0) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size ("abcdefg", 0) != sizeof ("abcdefg"))
|
||||
abort ();
|
||||
if (__builtin_object_size ("abcd\0efg", 0) != sizeof ("abcd\0efg"))
|
||||
abort ();
|
||||
if (__builtin_object_size (&"abcd\0efg", 0) != sizeof ("abcd\0efg"))
|
||||
abort ();
|
||||
if (__builtin_object_size (&"abcd\0efg"[0], 0) != sizeof ("abcd\0efg"))
|
||||
abort ();
|
||||
if (__builtin_object_size (&"abcd\0efg"[4], 0) != sizeof ("abcd\0efg") - 4)
|
||||
abort ();
|
||||
if (__builtin_object_size ("abcd\0efg" + 5, 0) != sizeof ("abcd\0efg") - 5)
|
||||
abort ();
|
||||
if (__builtin_object_size (L"abcdefg", 0) != sizeof (L"abcdefg"))
|
||||
abort ();
|
||||
r = (char *) L"abcd\0efg";
|
||||
if (__builtin_object_size (r + 2, 0) != sizeof (L"abcd\0efg") - 2)
|
||||
abort ();
|
||||
}
|
||||
|
||||
size_t l1 = 1;
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test2 (void)
|
||||
{
|
||||
struct B { char buf1[10]; char buf2[10]; } a;
|
||||
char *r, buf3[20];
|
||||
int i;
|
||||
|
||||
if (sizeof (a) != 20)
|
||||
return;
|
||||
|
||||
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];
|
||||
}
|
||||
if (__builtin_object_size (r, 0) != 20)
|
||||
abort ();
|
||||
r = &buf3[20];
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
if (i == l1 - 1)
|
||||
r = &a.buf1[7];
|
||||
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];
|
||||
}
|
||||
if (__builtin_object_size (r, 0) != 15)
|
||||
abort ();
|
||||
r += 8;
|
||||
if (__builtin_object_size (r, 0) != 7)
|
||||
abort ();
|
||||
if (__builtin_object_size (r + 6, 0) != 1)
|
||||
abort ();
|
||||
r = &buf3[18];
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
if (i == l1 - 1)
|
||||
r = &a.buf1[9];
|
||||
else if (i == l1)
|
||||
r = &a.buf2[9];
|
||||
else if (i == l1 + 1)
|
||||
r = &buf3[5];
|
||||
else if (i == l1 + 2)
|
||||
r = &a.buf1[4];
|
||||
}
|
||||
if (__builtin_object_size (r + 12, 0) != 4)
|
||||
abort ();
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test3 (void)
|
||||
{
|
||||
char buf4[10];
|
||||
struct B { struct A a[2]; struct A b; char c[4]; char d; double e;
|
||||
_Complex double f; } x;
|
||||
double y;
|
||||
_Complex double z;
|
||||
double *dp;
|
||||
|
||||
if (__builtin_object_size (buf4, 0) != sizeof (buf4))
|
||||
abort ();
|
||||
if (__builtin_object_size (&buf4, 0) != sizeof (buf4))
|
||||
abort ();
|
||||
if (__builtin_object_size (&buf4[0], 0) != sizeof (buf4))
|
||||
abort ();
|
||||
if (__builtin_object_size (&buf4[1], 0) != sizeof (buf4) - 1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x, 0) != sizeof (x))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a, 0) != sizeof (x))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0], 0) != sizeof (x))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0].a, 0) != sizeof (x))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0].a[0], 0) != sizeof (x))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0].a[3], 0) != sizeof (x) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0].b, 0)
|
||||
!= sizeof (x) - __builtin_offsetof (struct A, b))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[1].c, 0)
|
||||
!= sizeof (x) - sizeof (struct A) - __builtin_offsetof (struct A, c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[1].c[0], 0)
|
||||
!= sizeof (x) - sizeof (struct A) - __builtin_offsetof (struct A, c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[1].c[3], 0)
|
||||
!= sizeof (x) - sizeof (struct A) - __builtin_offsetof (struct A, c) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b, 0)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, b))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.a, 0)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, b))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.a[0], 0)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, b))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.a[3], 0)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, b) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.b, 0)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, b)
|
||||
- __builtin_offsetof (struct A, b))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.c, 0)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, b)
|
||||
- __builtin_offsetof (struct A, c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.c[0], 0)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, b)
|
||||
- __builtin_offsetof (struct A, c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.c[3], 0)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, b)
|
||||
- __builtin_offsetof (struct A, c) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.c, 0)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.c[0], 0)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.c[1], 0)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, c) - 1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.d, 0)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, d))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.e, 0)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, e))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.f, 0)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, f))
|
||||
abort ();
|
||||
dp = &__real__ x.f;
|
||||
if (__builtin_object_size (dp, 0)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, f))
|
||||
abort ();
|
||||
dp = &__imag__ x.f;
|
||||
if (__builtin_object_size (dp, 0)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, f)
|
||||
- sizeof (x.f) / 2)
|
||||
abort ();
|
||||
dp = &y;
|
||||
if (__builtin_object_size (dp, 0) != sizeof (y))
|
||||
abort ();
|
||||
if (__builtin_object_size (&z, 0) != sizeof (z))
|
||||
abort ();
|
||||
dp = &__real__ z;
|
||||
if (__builtin_object_size (dp, 0) != sizeof (z))
|
||||
abort ();
|
||||
dp = &__imag__ z;
|
||||
if (__builtin_object_size (dp, 0) != sizeof (z) / 2)
|
||||
abort ();
|
||||
}
|
||||
|
||||
struct S { unsigned int a; };
|
||||
|
||||
char *
|
||||
__attribute__ ((noinline))
|
||||
test4 (char *x, int y)
|
||||
{
|
||||
register int i;
|
||||
struct A *p;
|
||||
|
||||
for (i = 0; i < y; i++)
|
||||
{
|
||||
p = (struct A *) x;
|
||||
x = (char *) &p[1];
|
||||
if (__builtin_object_size (p, 0) != (size_t) -1)
|
||||
abort ();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test5 (size_t x)
|
||||
{
|
||||
char buf[64];
|
||||
char *p = &buf[8];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < x; ++i)
|
||||
p = p + 4;
|
||||
/* My understanding of ISO C99 6.5.6 is that a conforming
|
||||
program will not end up with p equal to &buf[0]
|
||||
through &buf[7], i.e. calling this function with say
|
||||
UINTPTR_MAX / 4 results in undefined behaviour.
|
||||
If that's true, then the maximum number of remaining
|
||||
bytes from p until end of the object is 56, otherwise
|
||||
it would be 64 (or conservative (size_t) -1 == unknown). */
|
||||
if (__builtin_object_size (p, 0) != sizeof (buf) - 8)
|
||||
abort ();
|
||||
memset (p, ' ', sizeof (buf) - 8 - 4 * 4);
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test6 (size_t x)
|
||||
{
|
||||
struct T { char buf[64]; char buf2[64]; } t;
|
||||
char *p = &t.buf[8];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < x; ++i)
|
||||
p = p + 4;
|
||||
if (__builtin_object_size (p, 0) != sizeof (t) - 8)
|
||||
abort ();
|
||||
memset (p, ' ', sizeof (t) - 8 - 4 * 4);
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test7 (void)
|
||||
{
|
||||
char buf[64];
|
||||
struct T { char buf[64]; char buf2[64]; } t;
|
||||
char *p = &buf[64], *q = &t.buf[64];
|
||||
|
||||
if (__builtin_object_size (p + 64, 0) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (q + 63, 0) != sizeof (t) - 64 - 63)
|
||||
abort ();
|
||||
if (__builtin_object_size (q + 64, 0) != sizeof (t) - 64 - 64)
|
||||
abort ();
|
||||
if (__builtin_object_size (q + 256, 0) != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test8 (void)
|
||||
{
|
||||
struct T { char buf[10]; char buf2[10]; } t;
|
||||
char *p = &t.buf2[-4];
|
||||
char *q = &t.buf2[0];
|
||||
if (__builtin_object_size (p, 0) != sizeof (t) - 10 + 4)
|
||||
abort ();
|
||||
if (__builtin_object_size (q, 0) != sizeof (t) - 10)
|
||||
abort ();
|
||||
/* GCC only handles additions, not subtractions. */
|
||||
q = q - 8;
|
||||
if (__builtin_object_size (q, 0) != (size_t) -1
|
||||
&& __builtin_object_size (q, 0) != sizeof (t) - 10 + 8)
|
||||
abort ();
|
||||
p = &t.buf[-4];
|
||||
if (__builtin_object_size (p, 0) != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
struct S s[10];
|
||||
__asm ("" : "=r" (l1) : "0" (l1));
|
||||
test1 (main, 6);
|
||||
test2 ();
|
||||
test3 ();
|
||||
test4 ((char *) s, 10);
|
||||
test5 (4);
|
||||
test6 (4);
|
||||
test7 ();
|
||||
test8 ();
|
||||
exit (0);
|
||||
}
|
393
gcc/testsuite/gcc.dg/builtin-object-size-2.c
Normal file
393
gcc/testsuite/gcc.dg/builtin-object-size-2.c
Normal file
|
@ -0,0 +1,393 @@
|
|||
/* { dg-do run } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
extern void abort (void);
|
||||
extern void exit (int);
|
||||
extern void *malloc (size_t);
|
||||
extern void *calloc (size_t, size_t);
|
||||
extern void *alloca (size_t);
|
||||
extern void *memcpy (void *, const void *, size_t);
|
||||
extern void *memset (void *, int, size_t);
|
||||
extern char *strcpy (char *, const char *);
|
||||
|
||||
struct A
|
||||
{
|
||||
char a[10];
|
||||
int b;
|
||||
char c[10];
|
||||
} y, w[4];
|
||||
|
||||
extern char exta[];
|
||||
extern char extb[30];
|
||||
extern struct A extc[];
|
||||
struct A zerol[0];
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test1 (void *q, int x)
|
||||
{
|
||||
struct A a;
|
||||
void *p = &a.a[3], *r;
|
||||
char var[x + 10];
|
||||
struct A vara[x + 10];
|
||||
if (x < 0)
|
||||
r = &a.a[9];
|
||||
else
|
||||
r = &a.c[1];
|
||||
if (__builtin_object_size (p, 1) != sizeof (a.a) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&a.c[9], 1)
|
||||
!= sizeof (a.c) - 9)
|
||||
abort ();
|
||||
if (__builtin_object_size (q, 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (r, 1) != sizeof (a.c) - 1)
|
||||
abort ();
|
||||
if (x < 6)
|
||||
r = &w[2].a[1];
|
||||
else
|
||||
r = &a.a[6];
|
||||
if (__builtin_object_size (&y, 1) != sizeof (y))
|
||||
abort ();
|
||||
if (__builtin_object_size (w, 1) != sizeof (w))
|
||||
abort ();
|
||||
if (__builtin_object_size (&y.b, 1) != sizeof (a.b))
|
||||
abort ();
|
||||
if (__builtin_object_size (r, 1) != sizeof (a.a) - 1)
|
||||
abort ();
|
||||
if (x < 20)
|
||||
r = malloc (30);
|
||||
else
|
||||
r = calloc (2, 16);
|
||||
if (__builtin_object_size (r, 1) != 2 * 16)
|
||||
abort ();
|
||||
if (x < 20)
|
||||
r = malloc (30);
|
||||
else
|
||||
r = calloc (2, 14);
|
||||
if (__builtin_object_size (r, 1) != 30)
|
||||
abort ();
|
||||
if (x < 30)
|
||||
r = malloc (sizeof (a));
|
||||
else
|
||||
r = &a.a[3];
|
||||
if (__builtin_object_size (r, 1) != sizeof (a))
|
||||
abort ();
|
||||
r = memcpy (r, "a", 2);
|
||||
if (__builtin_object_size (r, 1) != sizeof (a))
|
||||
abort ();
|
||||
r = memcpy (r + 2, "b", 2) + 2;
|
||||
if (__builtin_object_size (r, 1) != sizeof (a) - 4)
|
||||
abort ();
|
||||
r = &a.a[4];
|
||||
r = memset (r, 'a', 2);
|
||||
if (__builtin_object_size (r, 1) != sizeof (a.a) - 4)
|
||||
abort ();
|
||||
r = memset (r + 2, 'b', 2) + 2;
|
||||
if (__builtin_object_size (r, 1) != sizeof (a.a) - 8)
|
||||
abort ();
|
||||
r = &a.a[1];
|
||||
r = strcpy (r, "ab");
|
||||
if (__builtin_object_size (r, 1) != sizeof (a.a) - 1)
|
||||
abort ();
|
||||
r = strcpy (r + 2, "cd") + 2;
|
||||
if (__builtin_object_size (r, 1) != sizeof (a.a) - 5)
|
||||
abort ();
|
||||
if (__builtin_object_size (exta, 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (exta + 10, 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&exta[5], 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (extb, 1) != sizeof (extb))
|
||||
abort ();
|
||||
if (__builtin_object_size (extb + 10, 1) != sizeof (extb) - 10)
|
||||
abort ();
|
||||
if (__builtin_object_size (&extb[5], 1) != sizeof (extb) - 5)
|
||||
abort ();
|
||||
if (__builtin_object_size (extc, 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (extc + 10, 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&extc[5], 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&extc->a, 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&(extc + 10)->b, 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&extc[5].c[3], 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (var, 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (var + 10, 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&var[5], 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (vara, 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (vara + 10, 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&vara[5], 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&vara[0].a, 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&vara[10].a[0], 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&vara[5].a[4], 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&vara[5].b, 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&vara[7].c[7], 1) != (size_t) -1)
|
||||
abort ();
|
||||
if (__builtin_object_size (zerol, 1) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&zerol, 1) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&zerol[0], 1) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (zerol[0].a, 1) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&zerol[0].a[0], 1) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&zerol[0].b, 1) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size ("abcdefg", 1) != sizeof ("abcdefg"))
|
||||
abort ();
|
||||
if (__builtin_object_size ("abcd\0efg", 1) != sizeof ("abcd\0efg"))
|
||||
abort ();
|
||||
if (__builtin_object_size (&"abcd\0efg", 1) != sizeof ("abcd\0efg"))
|
||||
abort ();
|
||||
if (__builtin_object_size (&"abcd\0efg"[0], 1) != sizeof ("abcd\0efg"))
|
||||
abort ();
|
||||
if (__builtin_object_size (&"abcd\0efg"[4], 1) != sizeof ("abcd\0efg") - 4)
|
||||
abort ();
|
||||
if (__builtin_object_size ("abcd\0efg" + 5, 1) != sizeof ("abcd\0efg") - 5)
|
||||
abort ();
|
||||
if (__builtin_object_size (L"abcdefg", 1) != sizeof (L"abcdefg"))
|
||||
abort ();
|
||||
r = (char *) L"abcd\0efg";
|
||||
if (__builtin_object_size (r + 2, 1) != sizeof (L"abcd\0efg") - 2)
|
||||
abort ();
|
||||
}
|
||||
|
||||
size_t l1 = 1;
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test2 (void)
|
||||
{
|
||||
struct B { char buf1[10]; char buf2[10]; } a;
|
||||
char *r, buf3[20];
|
||||
int i;
|
||||
|
||||
if (sizeof (a) != 20)
|
||||
return;
|
||||
|
||||
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];
|
||||
}
|
||||
if (__builtin_object_size (r, 1) != sizeof (buf3))
|
||||
abort ();
|
||||
r = &buf3[20];
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
if (i == l1 - 1)
|
||||
r = &a.buf1[7];
|
||||
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];
|
||||
}
|
||||
if (__builtin_object_size (r, 1) != sizeof (buf3) - 5)
|
||||
abort ();
|
||||
r += 8;
|
||||
if (__builtin_object_size (r, 1) != sizeof (buf3) - 13)
|
||||
abort ();
|
||||
if (__builtin_object_size (r + 6, 1) != sizeof (buf3) - 19)
|
||||
abort ();
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test3 (void)
|
||||
{
|
||||
char buf4[10];
|
||||
struct B { struct A a[2]; struct A b; char c[4]; char d; double e;
|
||||
_Complex double f; } x;
|
||||
double y;
|
||||
_Complex double z;
|
||||
double *dp;
|
||||
|
||||
if (__builtin_object_size (buf4, 1) != sizeof (buf4))
|
||||
abort ();
|
||||
if (__builtin_object_size (&buf4, 1) != sizeof (buf4))
|
||||
abort ();
|
||||
if (__builtin_object_size (&buf4[0], 1) != sizeof (buf4))
|
||||
abort ();
|
||||
if (__builtin_object_size (&buf4[1], 1) != sizeof (buf4) - 1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x, 1) != sizeof (x))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a, 1) != sizeof (x.a))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0], 1) != sizeof (x.a))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0].a, 1) != sizeof (x.a[0].a))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0].a[0], 1) != sizeof (x.a[0].a))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0].a[3], 1) != sizeof (x.a[0].a) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0].b, 1) != sizeof (x.a[0].b))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[1].c, 1) != sizeof (x.a[1].c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[1].c[0], 1) != sizeof (x.a[1].c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[1].c[3], 1) != sizeof (x.a[1].c) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b, 1) != sizeof (x.b))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.a, 1) != sizeof (x.b.a))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.a[0], 1) != sizeof (x.b.a))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.a[3], 1) != sizeof (x.b.a) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.b, 1) != sizeof (x.b.b))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.c, 1) != sizeof (x.b.c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.c[0], 1) != sizeof (x.b.c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.c[3], 1) != sizeof (x.b.c) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.c, 1) != sizeof (x.c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.c[0], 1) != sizeof (x.c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.c[1], 1) != sizeof (x.c) - 1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.d, 1) != sizeof (x.d))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.e, 1) != sizeof (x.e))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.f, 1) != sizeof (x.f))
|
||||
abort ();
|
||||
dp = &__real__ x.f;
|
||||
if (__builtin_object_size (dp, 1) != sizeof (x.f) / 2)
|
||||
abort ();
|
||||
dp = &__imag__ x.f;
|
||||
if (__builtin_object_size (dp, 1) != sizeof (x.f) / 2)
|
||||
abort ();
|
||||
dp = &y;
|
||||
if (__builtin_object_size (dp, 1) != sizeof (y))
|
||||
abort ();
|
||||
if (__builtin_object_size (&z, 1) != sizeof (z))
|
||||
abort ();
|
||||
dp = &__real__ z;
|
||||
if (__builtin_object_size (dp, 1) != sizeof (z) / 2)
|
||||
abort ();
|
||||
dp = &__imag__ z;
|
||||
if (__builtin_object_size (dp, 1) != sizeof (z) / 2)
|
||||
abort ();
|
||||
}
|
||||
|
||||
struct S { unsigned int a; };
|
||||
|
||||
char *
|
||||
__attribute__ ((noinline))
|
||||
test4 (char *x, int y)
|
||||
{
|
||||
register int i;
|
||||
struct A *p;
|
||||
|
||||
for (i = 0; i < y; i++)
|
||||
{
|
||||
p = (struct A *) x;
|
||||
x = (char *) &p[1];
|
||||
if (__builtin_object_size (p, 1) != (size_t) -1)
|
||||
abort ();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test5 (size_t x)
|
||||
{
|
||||
struct T { char buf[64]; char buf2[64]; } t;
|
||||
char *p = &t.buf[8];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < x; ++i)
|
||||
p = p + 4;
|
||||
if (__builtin_object_size (p, 1) != sizeof (t.buf) - 8)
|
||||
abort ();
|
||||
memset (p, ' ', sizeof (t.buf) - 8 - 4 * 4);
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test6 (void)
|
||||
{
|
||||
char buf[64];
|
||||
struct T { char buf[64]; char buf2[64]; } t;
|
||||
char *p = &buf[64], *q = &t.buf[64];
|
||||
|
||||
if (__builtin_object_size (p + 64, 1) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (q + 0, 1) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (q + 64, 1) != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test7 (void)
|
||||
{
|
||||
struct T { char buf[10]; char buf2[10]; } t;
|
||||
char *p = &t.buf2[-4];
|
||||
char *q = &t.buf2[0];
|
||||
if (__builtin_object_size (p, 1) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (q, 1) != sizeof (t.buf2))
|
||||
abort ();
|
||||
q = &t.buf[10];
|
||||
if (__builtin_object_size (q, 1) != 0)
|
||||
abort ();
|
||||
q = &t.buf[11];
|
||||
if (__builtin_object_size (q, 1) != 0)
|
||||
abort ();
|
||||
p = &t.buf[-4];
|
||||
if (__builtin_object_size (p, 1) != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
struct S s[10];
|
||||
__asm ("" : "=r" (l1) : "0" (l1));
|
||||
test1 (main, 6);
|
||||
test2 ();
|
||||
test3 ();
|
||||
test4 ((char *) s, 10);
|
||||
test5 (4);
|
||||
test6 ();
|
||||
test7 ();
|
||||
exit (0);
|
||||
}
|
446
gcc/testsuite/gcc.dg/builtin-object-size-3.c
Normal file
446
gcc/testsuite/gcc.dg/builtin-object-size-3.c
Normal file
|
@ -0,0 +1,446 @@
|
|||
/* { dg-do run } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
extern void abort (void);
|
||||
extern void exit (int);
|
||||
extern void *malloc (size_t);
|
||||
extern void *calloc (size_t, size_t);
|
||||
extern void *alloca (size_t);
|
||||
extern void *memcpy (void *, const void *, size_t);
|
||||
extern void *memset (void *, int, size_t);
|
||||
extern char *strcpy (char *, const char *);
|
||||
|
||||
struct A
|
||||
{
|
||||
char a[10];
|
||||
int b;
|
||||
char c[10];
|
||||
} y, w[4];
|
||||
|
||||
extern char exta[];
|
||||
extern char extb[30];
|
||||
extern struct A zerol[0];
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test1 (void *q, int x)
|
||||
{
|
||||
struct A a;
|
||||
void *p = &a.a[3], *r;
|
||||
char var[x + 10];
|
||||
if (x < 0)
|
||||
r = &a.a[9];
|
||||
else
|
||||
r = &a.c[1];
|
||||
if (__builtin_object_size (p, 2)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, a) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&a.c[9], 2)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, c) - 9)
|
||||
abort ();
|
||||
if (__builtin_object_size (q, 2) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (r, 2)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, c) - 1)
|
||||
abort ();
|
||||
if (x < 6)
|
||||
r = &w[2].a[1];
|
||||
else
|
||||
r = &a.a[6];
|
||||
if (__builtin_object_size (&y, 2)
|
||||
!= sizeof (y))
|
||||
abort ();
|
||||
if (__builtin_object_size (w, 2)
|
||||
!= sizeof (w))
|
||||
abort ();
|
||||
if (__builtin_object_size (&y.b, 2)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, b))
|
||||
abort ();
|
||||
if (__builtin_object_size (r, 2)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, a) - 6)
|
||||
abort ();
|
||||
if (x < 20)
|
||||
r = malloc (30);
|
||||
else
|
||||
r = calloc (2, 16);
|
||||
if (__builtin_object_size (r, 2) != 30)
|
||||
abort ();
|
||||
if (x < 20)
|
||||
r = malloc (30);
|
||||
else
|
||||
r = calloc (2, 14);
|
||||
if (__builtin_object_size (r, 2) != 2 * 14)
|
||||
abort ();
|
||||
if (x < 30)
|
||||
r = malloc (sizeof (a));
|
||||
else
|
||||
r = &a.a[3];
|
||||
if (__builtin_object_size (r, 2)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, a) - 3)
|
||||
abort ();
|
||||
r = memcpy (r, "a", 2);
|
||||
if (__builtin_object_size (r, 2)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, a) - 3)
|
||||
abort ();
|
||||
r = memcpy (r + 2, "b", 2) + 2;
|
||||
if (__builtin_object_size (r, 2)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, a) - 3 - 4)
|
||||
abort ();
|
||||
r = &a.a[4];
|
||||
r = memset (r, 'a', 2);
|
||||
if (__builtin_object_size (r, 2)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, a) - 4)
|
||||
abort ();
|
||||
r = memset (r + 2, 'b', 2) + 2;
|
||||
if (__builtin_object_size (r, 2)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, a) - 8)
|
||||
abort ();
|
||||
r = &a.a[1];
|
||||
r = strcpy (r, "ab");
|
||||
if (__builtin_object_size (r, 2)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, a) - 1)
|
||||
abort ();
|
||||
r = strcpy (r + 2, "cd") + 2;
|
||||
if (__builtin_object_size (r, 2)
|
||||
!= sizeof (a) - __builtin_offsetof (struct A, a) - 5)
|
||||
abort ();
|
||||
if (__builtin_object_size (exta, 2) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (exta + 10, 2) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&exta[5], 2) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (extb, 2) != sizeof (extb))
|
||||
abort ();
|
||||
if (__builtin_object_size (extb + 10, 2) != sizeof (extb) - 10)
|
||||
abort ();
|
||||
if (__builtin_object_size (&extb[5], 2) != sizeof (extb) - 5)
|
||||
abort ();
|
||||
if (__builtin_object_size (var, 2) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (var + 10, 2) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&var[5], 2) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (zerol, 2) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&zerol, 2) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&zerol[0], 2) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (zerol[0].a, 2) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&zerol[0].a[0], 2) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&zerol[0].b, 2) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size ("abcdefg", 2) != sizeof ("abcdefg"))
|
||||
abort ();
|
||||
if (__builtin_object_size ("abcd\0efg", 2) != sizeof ("abcd\0efg"))
|
||||
abort ();
|
||||
if (__builtin_object_size (&"abcd\0efg", 2) != sizeof ("abcd\0efg"))
|
||||
abort ();
|
||||
if (__builtin_object_size (&"abcd\0efg"[0], 2) != sizeof ("abcd\0efg"))
|
||||
abort ();
|
||||
if (__builtin_object_size (&"abcd\0efg"[4], 2) != sizeof ("abcd\0efg") - 4)
|
||||
abort ();
|
||||
if (__builtin_object_size ("abcd\0efg" + 5, 2) != sizeof ("abcd\0efg") - 5)
|
||||
abort ();
|
||||
if (__builtin_object_size (L"abcdefg", 2) != sizeof (L"abcdefg"))
|
||||
abort ();
|
||||
r = (char *) L"abcd\0efg";
|
||||
if (__builtin_object_size (r + 2, 2) != sizeof (L"abcd\0efg") - 2)
|
||||
abort ();
|
||||
}
|
||||
|
||||
size_t l1 = 1;
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test2 (void)
|
||||
{
|
||||
struct B { char buf1[10]; char buf2[10]; } a;
|
||||
char *r, buf3[20];
|
||||
int i;
|
||||
|
||||
if (sizeof (a) != 20)
|
||||
return;
|
||||
|
||||
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];
|
||||
}
|
||||
if (__builtin_object_size (r, 2) != 3)
|
||||
abort ();
|
||||
r = &buf3[20];
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
if (i == l1 - 1)
|
||||
r = &a.buf1[7];
|
||||
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];
|
||||
}
|
||||
if (__builtin_object_size (r, 2) != 0)
|
||||
abort ();
|
||||
r = &buf3[2];
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
if (i == l1 - 1)
|
||||
r = &a.buf1[1];
|
||||
else if (i == l1)
|
||||
r = &a.buf1[2];
|
||||
else if (i == l1 + 1)
|
||||
r = &buf3[5];
|
||||
else if (i == l1 + 2)
|
||||
r = &a.buf1[4];
|
||||
}
|
||||
if (__builtin_object_size (r, 2) != 15)
|
||||
abort ();
|
||||
r += 8;
|
||||
if (__builtin_object_size (r, 2) != 7)
|
||||
abort ();
|
||||
if (__builtin_object_size (r + 6, 2) != 1)
|
||||
abort ();
|
||||
r = &buf3[18];
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
if (i == l1 - 1)
|
||||
r = &a.buf1[9];
|
||||
else if (i == l1)
|
||||
r = &a.buf2[9];
|
||||
else if (i == l1 + 1)
|
||||
r = &buf3[5];
|
||||
else if (i == l1 + 2)
|
||||
r = &a.buf1[4];
|
||||
}
|
||||
if (__builtin_object_size (r + 12, 2) != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test3 (void)
|
||||
{
|
||||
char buf4[10];
|
||||
struct B { struct A a[2]; struct A b; char c[4]; char d; double e;
|
||||
_Complex double f; } x;
|
||||
double y;
|
||||
_Complex double z;
|
||||
double *dp;
|
||||
|
||||
if (__builtin_object_size (buf4, 2) != sizeof (buf4))
|
||||
abort ();
|
||||
if (__builtin_object_size (&buf4, 2) != sizeof (buf4))
|
||||
abort ();
|
||||
if (__builtin_object_size (&buf4[0], 2) != sizeof (buf4))
|
||||
abort ();
|
||||
if (__builtin_object_size (&buf4[1], 2) != sizeof (buf4) - 1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x, 2) != sizeof (x))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a, 2) != sizeof (x))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0], 2) != sizeof (x))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0].a, 2) != sizeof (x))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0].a[0], 2) != sizeof (x))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0].a[3], 2) != sizeof (x) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0].b, 2)
|
||||
!= sizeof (x) - __builtin_offsetof (struct A, b))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[1].c, 2)
|
||||
!= sizeof (x) - sizeof (struct A) - __builtin_offsetof (struct A, c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[1].c[0], 2)
|
||||
!= sizeof (x) - sizeof (struct A) - __builtin_offsetof (struct A, c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[1].c[3], 2)
|
||||
!= sizeof (x) - sizeof (struct A) - __builtin_offsetof (struct A, c) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b, 2)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, b))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.a, 2)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, b))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.a[0], 2)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, b))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.a[3], 2)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, b) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.b, 2)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, b)
|
||||
- __builtin_offsetof (struct A, b))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.c, 2)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, b)
|
||||
- __builtin_offsetof (struct A, c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.c[0], 2)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, b)
|
||||
- __builtin_offsetof (struct A, c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.c[3], 2)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, b)
|
||||
- __builtin_offsetof (struct A, c) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.c, 2)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.c[0], 2)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.c[1], 2)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, c) - 1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.d, 2)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, d))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.e, 2)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, e))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.f, 2)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, f))
|
||||
abort ();
|
||||
dp = &__real__ x.f;
|
||||
if (__builtin_object_size (dp, 2)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, f))
|
||||
abort ();
|
||||
dp = &__imag__ x.f;
|
||||
if (__builtin_object_size (dp, 2)
|
||||
!= sizeof (x) - __builtin_offsetof (struct B, f)
|
||||
- sizeof (x.f) / 2)
|
||||
abort ();
|
||||
dp = &y;
|
||||
if (__builtin_object_size (dp, 2) != sizeof (y))
|
||||
abort ();
|
||||
if (__builtin_object_size (&z, 2) != sizeof (z))
|
||||
abort ();
|
||||
dp = &__real__ z;
|
||||
if (__builtin_object_size (dp, 2) != sizeof (z))
|
||||
abort ();
|
||||
dp = &__imag__ z;
|
||||
if (__builtin_object_size (dp, 2) != sizeof (z) / 2)
|
||||
abort ();
|
||||
}
|
||||
|
||||
struct S { unsigned int a; };
|
||||
|
||||
char *
|
||||
__attribute__ ((noinline))
|
||||
test4 (char *x, int y)
|
||||
{
|
||||
register int i;
|
||||
struct A *p;
|
||||
|
||||
for (i = 0; i < y; i++)
|
||||
{
|
||||
p = (struct A *) x;
|
||||
x = (char *) &p[1];
|
||||
if (__builtin_object_size (p, 2) != 0)
|
||||
abort ();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test5 (size_t x)
|
||||
{
|
||||
char buf[64];
|
||||
char *p = &buf[8];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < x; ++i)
|
||||
p = p + 4;
|
||||
if (__builtin_object_size (p, 2) != 0)
|
||||
abort ();
|
||||
memset (p, ' ', sizeof (buf) - 8 - 4 * 4);
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test6 (size_t x)
|
||||
{
|
||||
struct T { char buf[64]; char buf2[64]; } t;
|
||||
char *p = &t.buf[8];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < x; ++i)
|
||||
p = p + 4;
|
||||
if (__builtin_object_size (p, 2) != 0)
|
||||
abort ();
|
||||
memset (p, ' ', sizeof (t) - 8 - 4 * 4);
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test7 (void)
|
||||
{
|
||||
char buf[64];
|
||||
struct T { char buf[64]; char buf2[64]; } t;
|
||||
char *p = &buf[64], *q = &t.buf[64];
|
||||
|
||||
if (__builtin_object_size (p + 64, 2) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (q + 63, 2) != sizeof (t) - 64 - 63)
|
||||
abort ();
|
||||
if (__builtin_object_size (q + 64, 2) != sizeof (t) - 64 - 64)
|
||||
abort ();
|
||||
if (__builtin_object_size (q + 256, 2) != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test8 (void)
|
||||
{
|
||||
struct T { char buf[10]; char buf2[10]; } t;
|
||||
char *p = &t.buf2[-4];
|
||||
char *q = &t.buf2[0];
|
||||
if (__builtin_object_size (p, 2) != sizeof (t) - 10 + 4)
|
||||
abort ();
|
||||
if (__builtin_object_size (q, 2) != sizeof (t) - 10)
|
||||
abort ();
|
||||
/* GCC only handles additions, not subtractions. */
|
||||
q = q - 8;
|
||||
if (__builtin_object_size (q, 2) != 0
|
||||
&& __builtin_object_size (q, 2) != sizeof (t) - 10 + 8)
|
||||
abort ();
|
||||
p = &t.buf[-4];
|
||||
if (__builtin_object_size (p, 2) != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
struct S s[10];
|
||||
__asm ("" : "=r" (l1) : "0" (l1));
|
||||
test1 (main, 6);
|
||||
test2 ();
|
||||
test3 ();
|
||||
test4 ((char *) s, 10);
|
||||
test5 (4);
|
||||
test6 (4);
|
||||
test7 ();
|
||||
test8 ();
|
||||
exit (0);
|
||||
}
|
407
gcc/testsuite/gcc.dg/builtin-object-size-4.c
Normal file
407
gcc/testsuite/gcc.dg/builtin-object-size-4.c
Normal file
|
@ -0,0 +1,407 @@
|
|||
/* { dg-do run } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
extern void abort (void);
|
||||
extern void exit (int);
|
||||
extern void *malloc (size_t);
|
||||
extern void *calloc (size_t, size_t);
|
||||
extern void *alloca (size_t);
|
||||
extern void *memcpy (void *, const void *, size_t);
|
||||
extern void *memset (void *, int, size_t);
|
||||
extern char *strcpy (char *, const char *);
|
||||
|
||||
struct A
|
||||
{
|
||||
char a[10];
|
||||
int b;
|
||||
char c[10];
|
||||
} y, w[4];
|
||||
|
||||
extern char exta[];
|
||||
extern char extb[30];
|
||||
extern struct A extc[];
|
||||
struct A zerol[0];
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test1 (void *q, int x)
|
||||
{
|
||||
struct A a;
|
||||
void *p = &a.a[3], *r;
|
||||
char var[x + 10];
|
||||
struct A vara[x + 10];
|
||||
if (x < 0)
|
||||
r = &a.a[9];
|
||||
else
|
||||
r = &a.c[1];
|
||||
if (__builtin_object_size (p, 3) != sizeof (a.a) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&a.c[9], 3)
|
||||
!= sizeof (a.c) - 9)
|
||||
abort ();
|
||||
if (__builtin_object_size (q, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (r, 3) != sizeof (a.a) - 9)
|
||||
abort ();
|
||||
if (x < 6)
|
||||
r = &w[2].a[1];
|
||||
else
|
||||
r = &a.a[6];
|
||||
if (__builtin_object_size (&y, 3) != sizeof (y))
|
||||
abort ();
|
||||
if (__builtin_object_size (w, 3) != sizeof (w))
|
||||
abort ();
|
||||
if (__builtin_object_size (&y.b, 3) != sizeof (a.b))
|
||||
abort ();
|
||||
if (__builtin_object_size (r, 3) != sizeof (a.a) - 6)
|
||||
abort ();
|
||||
if (x < 20)
|
||||
r = malloc (30);
|
||||
else
|
||||
r = calloc (2, 16);
|
||||
if (__builtin_object_size (r, 3) != 30)
|
||||
abort ();
|
||||
if (x < 20)
|
||||
r = malloc (30);
|
||||
else
|
||||
r = calloc (2, 14);
|
||||
if (__builtin_object_size (r, 3) != 2 * 14)
|
||||
abort ();
|
||||
if (x < 30)
|
||||
r = malloc (sizeof (a));
|
||||
else
|
||||
r = &a.a[3];
|
||||
if (__builtin_object_size (r, 3) != sizeof (a.a) - 3)
|
||||
abort ();
|
||||
r = memcpy (r, "a", 2);
|
||||
if (__builtin_object_size (r, 3) != sizeof (a.a) - 3)
|
||||
abort ();
|
||||
r = memcpy (r + 2, "b", 2) + 2;
|
||||
if (__builtin_object_size (r, 3) != sizeof (a.a) - 3 - 4)
|
||||
abort ();
|
||||
r = &a.a[4];
|
||||
r = memset (r, 'a', 2);
|
||||
if (__builtin_object_size (r, 3) != sizeof (a.a) - 4)
|
||||
abort ();
|
||||
r = memset (r + 2, 'b', 2) + 2;
|
||||
if (__builtin_object_size (r, 3) != sizeof (a.a) - 8)
|
||||
abort ();
|
||||
r = &a.a[1];
|
||||
r = strcpy (r, "ab");
|
||||
if (__builtin_object_size (r, 3) != sizeof (a.a) - 1)
|
||||
abort ();
|
||||
r = strcpy (r + 2, "cd") + 2;
|
||||
if (__builtin_object_size (r, 3) != sizeof (a.a) - 5)
|
||||
abort ();
|
||||
if (__builtin_object_size (exta, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (exta + 10, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&exta[5], 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (extb, 3) != sizeof (extb))
|
||||
abort ();
|
||||
if (__builtin_object_size (extb + 10, 3) != sizeof (extb) - 10)
|
||||
abort ();
|
||||
if (__builtin_object_size (&extb[5], 3) != sizeof (extb) - 5)
|
||||
abort ();
|
||||
if (__builtin_object_size (extc, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (extc + 10, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&extc[5], 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&extc->a, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&(extc + 10)->b, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&extc[5].c[3], 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (var, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (var + 10, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&var[5], 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (vara, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (vara + 10, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&vara[5], 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&vara[0].a, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&vara[10].a[0], 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&vara[5].a[4], 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&vara[5].b, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&vara[7].c[7], 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (zerol, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&zerol, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&zerol[0], 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (zerol[0].a, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&zerol[0].a[0], 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (&zerol[0].b, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size ("abcdefg", 3) != sizeof ("abcdefg"))
|
||||
abort ();
|
||||
if (__builtin_object_size ("abcd\0efg", 3) != sizeof ("abcd\0efg"))
|
||||
abort ();
|
||||
if (__builtin_object_size (&"abcd\0efg", 3) != sizeof ("abcd\0efg"))
|
||||
abort ();
|
||||
if (__builtin_object_size (&"abcd\0efg"[0], 3) != sizeof ("abcd\0efg"))
|
||||
abort ();
|
||||
if (__builtin_object_size (&"abcd\0efg"[4], 3) != sizeof ("abcd\0efg") - 4)
|
||||
abort ();
|
||||
if (__builtin_object_size ("abcd\0efg" + 5, 3) != sizeof ("abcd\0efg") - 5)
|
||||
abort ();
|
||||
if (__builtin_object_size (L"abcdefg", 3) != sizeof (L"abcdefg"))
|
||||
abort ();
|
||||
r = (char *) L"abcd\0efg";
|
||||
if (__builtin_object_size (r + 2, 3) != sizeof (L"abcd\0efg") - 2)
|
||||
abort ();
|
||||
}
|
||||
|
||||
size_t l1 = 1;
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test2 (void)
|
||||
{
|
||||
struct B { char buf1[10]; char buf2[10]; } a;
|
||||
char *r, buf3[20];
|
||||
int i;
|
||||
|
||||
if (sizeof (a) != 20)
|
||||
return;
|
||||
|
||||
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];
|
||||
}
|
||||
if (__builtin_object_size (r, 3) != sizeof (a.buf1) - 9)
|
||||
abort ();
|
||||
r = &buf3[20];
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
if (i == l1 - 1)
|
||||
r = &a.buf1[7];
|
||||
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];
|
||||
}
|
||||
if (__builtin_object_size (r, 3) != 0)
|
||||
abort ();
|
||||
r = &buf3[1];
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
if (i == l1 - 1)
|
||||
r = &a.buf1[6];
|
||||
else if (i == l1)
|
||||
r = &a.buf2[4];
|
||||
else if (i == l1 + 1)
|
||||
r = &buf3[5];
|
||||
else if (i == l1 + 2)
|
||||
r = &a.buf1[2];
|
||||
}
|
||||
if (__builtin_object_size (r, 3) != sizeof (a.buf1) - 6)
|
||||
abort ();
|
||||
r += 2;
|
||||
if (__builtin_object_size (r, 3) != sizeof (a.buf1) - 6 - 2)
|
||||
abort ();
|
||||
if (__builtin_object_size (r + 1, 3) != sizeof (a.buf1) - 6 - 3)
|
||||
abort ();
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test3 (void)
|
||||
{
|
||||
char buf4[10];
|
||||
struct B { struct A a[2]; struct A b; char c[4]; char d; double e;
|
||||
_Complex double f; } x;
|
||||
double y;
|
||||
_Complex double z;
|
||||
double *dp;
|
||||
|
||||
if (__builtin_object_size (buf4, 3) != sizeof (buf4))
|
||||
abort ();
|
||||
if (__builtin_object_size (&buf4, 3) != sizeof (buf4))
|
||||
abort ();
|
||||
if (__builtin_object_size (&buf4[0], 3) != sizeof (buf4))
|
||||
abort ();
|
||||
if (__builtin_object_size (&buf4[1], 3) != sizeof (buf4) - 1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x, 3) != sizeof (x))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a, 3) != sizeof (x.a))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0], 3) != sizeof (x.a))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0].a, 3) != sizeof (x.a[0].a))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0].a[0], 3) != sizeof (x.a[0].a))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0].a[3], 3) != sizeof (x.a[0].a) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[0].b, 3) != sizeof (x.a[0].b))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[1].c, 3) != sizeof (x.a[1].c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[1].c[0], 3) != sizeof (x.a[1].c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.a[1].c[3], 3) != sizeof (x.a[1].c) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b, 3) != sizeof (x.b))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.a, 3) != sizeof (x.b.a))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.a[0], 3) != sizeof (x.b.a))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.a[3], 3) != sizeof (x.b.a) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.b, 3) != sizeof (x.b.b))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.c, 3) != sizeof (x.b.c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.c[0], 3) != sizeof (x.b.c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.b.c[3], 3) != sizeof (x.b.c) - 3)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.c, 3) != sizeof (x.c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.c[0], 3) != sizeof (x.c))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.c[1], 3) != sizeof (x.c) - 1)
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.d, 3) != sizeof (x.d))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.e, 3) != sizeof (x.e))
|
||||
abort ();
|
||||
if (__builtin_object_size (&x.f, 3) != sizeof (x.f))
|
||||
abort ();
|
||||
dp = &__real__ x.f;
|
||||
if (__builtin_object_size (dp, 3) != sizeof (x.f) / 2)
|
||||
abort ();
|
||||
dp = &__imag__ x.f;
|
||||
if (__builtin_object_size (dp, 3) != sizeof (x.f) / 2)
|
||||
abort ();
|
||||
dp = &y;
|
||||
if (__builtin_object_size (dp, 3) != sizeof (y))
|
||||
abort ();
|
||||
if (__builtin_object_size (&z, 3) != sizeof (z))
|
||||
abort ();
|
||||
dp = &__real__ z;
|
||||
if (__builtin_object_size (dp, 3) != sizeof (z) / 2)
|
||||
abort ();
|
||||
dp = &__imag__ z;
|
||||
if (__builtin_object_size (dp, 3) != sizeof (z) / 2)
|
||||
abort ();
|
||||
}
|
||||
|
||||
struct S { unsigned int a; };
|
||||
|
||||
char *
|
||||
__attribute__ ((noinline))
|
||||
test4 (char *x, int y)
|
||||
{
|
||||
register int i;
|
||||
struct A *p;
|
||||
|
||||
for (i = 0; i < y; i++)
|
||||
{
|
||||
p = (struct A *) x;
|
||||
x = (char *) &p[1];
|
||||
if (__builtin_object_size (p, 3) != 0)
|
||||
abort ();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test5 (size_t x)
|
||||
{
|
||||
struct T { char buf[64]; char buf2[64]; } t;
|
||||
char *p = &t.buf[8];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < x; ++i)
|
||||
p = p + 4;
|
||||
if (__builtin_object_size (p, 3) != 0)
|
||||
abort ();
|
||||
memset (p, ' ', sizeof (t.buf) - 8 - 4 * 4);
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test6 (void)
|
||||
{
|
||||
char buf[64];
|
||||
struct T { char buf[64]; char buf2[64]; } t;
|
||||
char *p = &buf[64], *q = &t.buf[64];
|
||||
|
||||
if (__builtin_object_size (p + 64, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (q + 0, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (q + 64, 3) != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noinline))
|
||||
test7 (void)
|
||||
{
|
||||
struct T { char buf[10]; char buf2[10]; } t;
|
||||
char *p = &t.buf2[-4];
|
||||
char *q = &t.buf2[0];
|
||||
if (__builtin_object_size (p, 3) != 0)
|
||||
abort ();
|
||||
if (__builtin_object_size (q, 3) != sizeof (t.buf2))
|
||||
abort ();
|
||||
q = &t.buf[10];
|
||||
if (__builtin_object_size (q, 3) != 0)
|
||||
abort ();
|
||||
q = &t.buf[11];
|
||||
if (__builtin_object_size (q, 3) != 0)
|
||||
abort ();
|
||||
p = &t.buf[-4];
|
||||
if (__builtin_object_size (p, 3) != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
struct S s[10];
|
||||
__asm ("" : "=r" (l1) : "0" (l1));
|
||||
test1 (main, 6);
|
||||
test2 ();
|
||||
test3 ();
|
||||
test4 ((char *) s, 10);
|
||||
test5 (4);
|
||||
test6 ();
|
||||
test7 ();
|
||||
exit (0);
|
||||
}
|
56
gcc/testsuite/gcc.dg/builtin-object-size-5.c
Normal file
56
gcc/testsuite/gcc.dg/builtin-object-size-5.c
Normal file
|
@ -0,0 +1,56 @@
|
|||
/* { dg-do compile { target i?86-*-linux* x86_64-*-linux* } } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
extern void abort (void);
|
||||
extern char buf[0x40000000];
|
||||
|
||||
void
|
||||
test1 (size_t x)
|
||||
{
|
||||
char *p = &buf[8];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < x; ++i)
|
||||
p = p + 4;
|
||||
if (__builtin_object_size (p, 0) != sizeof (buf) - 8)
|
||||
abort ();
|
||||
}
|
||||
|
||||
void
|
||||
test2 (size_t x)
|
||||
{
|
||||
char *p = &buf[8];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < x; ++i)
|
||||
p = p + 4;
|
||||
if (__builtin_object_size (p, 1) != sizeof (buf) - 8)
|
||||
abort ();
|
||||
}
|
||||
|
||||
void
|
||||
test3 (size_t x)
|
||||
{
|
||||
char *p = &buf[8];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < x; ++i)
|
||||
p = p + 4;
|
||||
if (__builtin_object_size (p, 2) != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
void
|
||||
test4 (size_t x)
|
||||
{
|
||||
char *p = &buf[8];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < x; ++i)
|
||||
p = p + 4;
|
||||
if (__builtin_object_size (p, 3) != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* { dg-final { scan-assembler-not "abort" } } */
|
113
gcc/testsuite/gcc.dg/builtin-stringop-chk-1.c
Normal file
113
gcc/testsuite/gcc.dg/builtin-stringop-chk-1.c
Normal file
|
@ -0,0 +1,113 @@
|
|||
/* Test whether buffer overflow warnings for __*_chk builtins
|
||||
are emitted properly. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -std=gnu99" } */
|
||||
|
||||
extern void abort (void);
|
||||
|
||||
#include "../gcc.c-torture/execute/builtins/chk.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
volatile void *vx;
|
||||
char buf1[20];
|
||||
int x;
|
||||
|
||||
void
|
||||
test (int arg, ...)
|
||||
{
|
||||
char buf2[20];
|
||||
va_list ap;
|
||||
char *p = &buf1[10], *q;
|
||||
|
||||
memcpy (&buf2[19], "ab", 1);
|
||||
memcpy (&buf2[19], "ab", 2); /* { dg-warning "will always overflow" "memcpy" } */
|
||||
vx = mempcpy (&buf2[19], "ab", 1);
|
||||
vx = mempcpy (&buf2[19], "ab", 2); /* { dg-warning "will always overflow" "mempcpy" } */
|
||||
memmove (&buf2[18], &buf1[10], 2);
|
||||
memmove (&buf2[18], &buf1[10], 3); /* { dg-warning "will always overflow" "memmove" } */
|
||||
memset (&buf2[16], 'a', 4);
|
||||
memset (&buf2[15], 'b', 6); /* { dg-warning "will always overflow" "memset" } */
|
||||
strcpy (&buf2[18], "a");
|
||||
strcpy (&buf2[18], "ab"); /* { dg-warning "will always overflow" "strcpy" } */
|
||||
vx = stpcpy (&buf2[18], "a");
|
||||
vx = stpcpy (&buf2[18], "ab"); /* { dg-warning "will always overflow" "stpcpy" } */
|
||||
strncpy (&buf2[18], "a", 2);
|
||||
strncpy (&buf2[18], "a", 3); /* { dg-warning "will always overflow" "strncpy" } */
|
||||
strncpy (&buf2[18], "abc", 2);
|
||||
strncpy (&buf2[18], "abc", 3); /* { dg-warning "will always overflow" "strncpy" } */
|
||||
memset (buf2, '\0', sizeof (buf2));
|
||||
strcat (&buf2[18], "a");
|
||||
memset (buf2, '\0', sizeof (buf2));
|
||||
strcat (&buf2[18], "ab"); /* { dg-warning "will always overflow" "strcat" } */
|
||||
sprintf (&buf2[18], "%s", buf1);
|
||||
sprintf (&buf2[18], "%s", "a");
|
||||
sprintf (&buf2[18], "%s", "ab"); /* { dg-warning "will always overflow" "sprintf" } */
|
||||
sprintf (&buf2[18], "a");
|
||||
sprintf (&buf2[18], "ab"); /* { dg-warning "will always overflow" "sprintf" } */
|
||||
snprintf (&buf2[18], 2, "%d", x);
|
||||
/* N argument to snprintf is the size of the buffer.
|
||||
Although this particular call wouldn't overflow buf2,
|
||||
incorrect buffer size was passed to it and therefore
|
||||
we want a warning and runtime failure. */
|
||||
snprintf (&buf2[18], 3, "%d", x); /* { dg-warning "will always overflow" "snprintf" } */
|
||||
va_start (ap, arg);
|
||||
vsprintf (&buf2[18], "a", ap);
|
||||
va_end (ap);
|
||||
va_start (ap, arg);
|
||||
vsprintf (&buf2[18], "ab", ap); /* { dg-warning "will always overflow" "vsprintf" } */
|
||||
va_end (ap);
|
||||
va_start (ap, arg);
|
||||
vsnprintf (&buf2[18], 2, "%s", ap);
|
||||
va_end (ap);
|
||||
va_start (ap, arg);
|
||||
/* See snprintf above. */
|
||||
vsnprintf (&buf2[18], 3, "%s", ap); /* { dg-warning "will always overflow" "vsnprintf" } */
|
||||
va_end (ap);
|
||||
|
||||
p = p + 10;
|
||||
memset (p, 'd', 0);
|
||||
q = strcpy (p, ""); /* { dg-warning "will always overflow" "strcpy" } */
|
||||
|
||||
/* This invokes undefined behaviour, since we are past the end of buf1. */
|
||||
p = p + 10;
|
||||
memset (p, 'd', 1); /* { dg-warning "will always overflow" "memset" } */
|
||||
|
||||
memset (q, 'd', 0);
|
||||
memset (q, 'd', 1); /* { dg-warning "will always overflow" "memset" } */
|
||||
q = q - 10;
|
||||
memset (q, 'd', 10);
|
||||
}
|
||||
|
||||
char *str = "ABCDEFG";
|
||||
typedef struct { char b[16]; } H;
|
||||
|
||||
/* Some brown paper bag bugs found in real applications.
|
||||
This test is here merely for amusement. */
|
||||
|
||||
void
|
||||
test2 (const H h)
|
||||
{
|
||||
char c;
|
||||
strncpy (&c, str, 3); /* { dg-warning "will always overflow" "strncpy" } */
|
||||
|
||||
struct { char b[4]; } x;
|
||||
sprintf (x.b, "%s", "ABCD"); /* { dg-warning "will always overflow" "sprintf" } */
|
||||
|
||||
unsigned int i;
|
||||
memcpy (&i, &h, sizeof (h)); /* { dg-warning "will always overflow" "memcpy" } */
|
||||
|
||||
unsigned char buf[21];
|
||||
memset (buf + 16, 0, 8); /* { dg-warning "will always overflow" "memset" } */
|
||||
|
||||
typedef struct { int i, j, k, l; } S;
|
||||
S *s[3];
|
||||
memset (s, 0, sizeof (S) * 3); /* { dg-warning "will always overflow" "memset" } */
|
||||
|
||||
struct T { char a[8]; char b[4]; char c[10]; } t;
|
||||
stpcpy (t.c,"Testing..."); /* { dg-warning "will always overflow" "stpcpy" } */
|
||||
|
||||
char b1[7];
|
||||
char b2[4];
|
||||
memset (b1, 0, sizeof (b1));
|
||||
memset (b2, 0, sizeof (b1)); /* { dg-warning "will always overflow" "memset" } */
|
||||
}
|
137
gcc/testsuite/gcc.dg/builtin-stringop-chk-2.c
Normal file
137
gcc/testsuite/gcc.dg/builtin-stringop-chk-2.c
Normal file
|
@ -0,0 +1,137 @@
|
|||
/* This file was miscompiled by an earlier version of the object size
|
||||
checking patch. Object size in one of the memcpy calls was
|
||||
incorrectly determined to be 0 while it should be (size_t) -1
|
||||
(== unknown). */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
#include "../gcc.c-torture/execute/builtins/chk.h"
|
||||
|
||||
void *bar (int);
|
||||
extern void *malloc (__SIZE_TYPE__);
|
||||
|
||||
struct A
|
||||
{
|
||||
int i, j, k;
|
||||
};
|
||||
|
||||
/* Here all object sizes are not known at compile time. There
|
||||
should be no warning, nor any checker functions called. */
|
||||
|
||||
void
|
||||
foo (const struct A *x, int y, const unsigned char *z)
|
||||
{
|
||||
unsigned int b;
|
||||
unsigned char *c = 0;
|
||||
|
||||
b = (x->i & 0xff) == 1 ? 3 : 4;
|
||||
if (y)
|
||||
c = bar (x->j * x->k);
|
||||
|
||||
const unsigned char *d = z;
|
||||
unsigned char *e = c;
|
||||
unsigned char *f = c + x->j * x->k;
|
||||
int g = 0;
|
||||
|
||||
while (e < f)
|
||||
{
|
||||
unsigned int h = *d++;
|
||||
|
||||
if (h & 128)
|
||||
{
|
||||
h = h - 128;
|
||||
g = e + h * b > f;
|
||||
if (g)
|
||||
h = (f - e) / b;
|
||||
if (b < 4)
|
||||
do
|
||||
{
|
||||
memcpy (e, d, 3);
|
||||
e += 3;
|
||||
}
|
||||
while (--h);
|
||||
else
|
||||
do
|
||||
{
|
||||
memcpy (e, d, 4);
|
||||
e += 4;
|
||||
}
|
||||
while (--h);
|
||||
d += b;
|
||||
}
|
||||
else
|
||||
{
|
||||
h *= b;
|
||||
g = e + h > f;
|
||||
if (g)
|
||||
h = f - e;
|
||||
memcpy (e, d, h);
|
||||
e += h;
|
||||
d += h;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The same routine, slightly modified:
|
||||
1) c has known size at compile time
|
||||
2) e += h was changed into e += 16.
|
||||
GCC could actually through VRP determine that
|
||||
in e += h is (h >= 0 && h <= 127), thus know
|
||||
it is pointer addition and not subtraction and
|
||||
know e's __builtin_object_size (e, 0) is at 512,
|
||||
but we are not there yet. */
|
||||
|
||||
unsigned char *
|
||||
baz (const struct A *x, const unsigned char *z)
|
||||
{
|
||||
unsigned int b;
|
||||
unsigned char *c = 0;
|
||||
|
||||
b = (x->i & 0xff) == 1 ? 3 : 4;
|
||||
c = malloc (512);
|
||||
|
||||
const unsigned char *d = z;
|
||||
unsigned char *e = c;
|
||||
unsigned char *f = c + x->j * x->k;
|
||||
int g = 0;
|
||||
|
||||
while (e < f)
|
||||
{
|
||||
unsigned int h = *d++;
|
||||
|
||||
if (h & 128)
|
||||
{
|
||||
h = h - 128;
|
||||
g = e + h * b > f;
|
||||
if (g)
|
||||
h = (f - e) / b;
|
||||
if (b < 4)
|
||||
do
|
||||
{
|
||||
memcpy (e, d, 3);
|
||||
e += 3;
|
||||
}
|
||||
while (--h);
|
||||
else
|
||||
do
|
||||
{
|
||||
memcpy (e, d, 513); /* { dg-warning "will always overflow" "memcpy" } */
|
||||
e += 4;
|
||||
}
|
||||
while (--h);
|
||||
d += b;
|
||||
}
|
||||
else
|
||||
{
|
||||
h *= b;
|
||||
g = e + h > f;
|
||||
if (g)
|
||||
h = f - e;
|
||||
memcpy (e, d, h);
|
||||
/* e += h; */
|
||||
e += 16;
|
||||
d += h;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
40
gcc/testsuite/gcc.dg/tree-ssa/builtin-fprintf-1.c
Normal file
40
gcc/testsuite/gcc.dg/tree-ssa/builtin-fprintf-1.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-fab" } */
|
||||
|
||||
typedef struct { int i; } FILE;
|
||||
FILE *fp;
|
||||
extern int fprintf (FILE *, const char *, ...);
|
||||
volatile int vi0, vi1, vi2, vi3, vi4, vi5, vi6, vi7, vi8, vi9;
|
||||
|
||||
void test (void)
|
||||
{
|
||||
vi0 = 0;
|
||||
fprintf (fp, "hello");
|
||||
vi1 = 0;
|
||||
fprintf (fp, "hello\n");
|
||||
vi2 = 0;
|
||||
fprintf (fp, "a");
|
||||
vi3 = 0;
|
||||
fprintf (fp, "");
|
||||
vi4 = 0;
|
||||
fprintf (fp, "%s", "hello");
|
||||
vi5 = 0;
|
||||
fprintf (fp, "%s", "hello\n");
|
||||
vi6 = 0;
|
||||
fprintf (fp, "%s", "a");
|
||||
vi7 = 0;
|
||||
fprintf (fp, "%c", 'x');
|
||||
vi8 = 0;
|
||||
fprintf (fp, "%d%d", vi0, vi1);
|
||||
vi9 = 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump "vi0.*fwrite.*\"hello\".*1, 5, fp.*vi1" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi1.*fwrite.*\"hello\\\\n\".*1, 6, fp.*vi2" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi2.*fputc.*fp.*vi3" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi3 = 0\[^\(\)\]*vi4 = 0" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi4.*fwrite.*\"hello\".*1, 5, fp.*vi5" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi5.*fwrite.*\"hello\\\\n\".*1, 6, fp.*vi6" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi6.*fputc.*fp.*vi7" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi7.*fputc.*fp.*vi8" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi8.*fprintf.*fp.*\"%d%d\".*vi9" "fab"} } */
|
40
gcc/testsuite/gcc.dg/tree-ssa/builtin-fprintf-chk-1.c
Normal file
40
gcc/testsuite/gcc.dg/tree-ssa/builtin-fprintf-chk-1.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-fab" } */
|
||||
|
||||
typedef struct { int i; } FILE;
|
||||
FILE *fp;
|
||||
extern int __fprintf_chk (FILE *, int, const char *, ...);
|
||||
volatile int vi0, vi1, vi2, vi3, vi4, vi5, vi6, vi7, vi8, vi9;
|
||||
|
||||
void test (void)
|
||||
{
|
||||
vi0 = 0;
|
||||
__fprintf_chk (fp, 1, "hello");
|
||||
vi1 = 0;
|
||||
__fprintf_chk (fp, 1, "hello\n");
|
||||
vi2 = 0;
|
||||
__fprintf_chk (fp, 1, "a");
|
||||
vi3 = 0;
|
||||
__fprintf_chk (fp, 1, "");
|
||||
vi4 = 0;
|
||||
__fprintf_chk (fp, 1, "%s", "hello");
|
||||
vi5 = 0;
|
||||
__fprintf_chk (fp, 1, "%s", "hello\n");
|
||||
vi6 = 0;
|
||||
__fprintf_chk (fp, 1, "%s", "a");
|
||||
vi7 = 0;
|
||||
__fprintf_chk (fp, 1, "%c", 'x');
|
||||
vi8 = 0;
|
||||
__fprintf_chk (fp, 1, "%d%d", vi0, vi1);
|
||||
vi9 = 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump "vi0.*fwrite.*\"hello\".*1, 5, fp.*vi1" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi1.*fwrite.*\"hello\\\\n\".*1, 6, fp.*vi2" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi2.*fputc.*fp.*vi3" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi3 = 0\[^\(\)\]*vi4 = 0" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi4.*fwrite.*\"hello\".*1, 5, fp.*vi5" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi5.*fwrite.*\"hello\\\\n\".*1, 6, fp.*vi6" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi6.*fputc.*fp.*vi7" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi7.*fputc.*fp.*vi8" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi8.*__fprintf_chk.*fp.*1.*\"%d%d\".*vi9" "fab"} } */
|
41
gcc/testsuite/gcc.dg/tree-ssa/builtin-printf-1.c
Normal file
41
gcc/testsuite/gcc.dg/tree-ssa/builtin-printf-1.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-fab" } */
|
||||
|
||||
extern int printf (const char *, ...);
|
||||
volatile int vi0, vi1, vi2, vi3, vi4, vi5, vi6, vi7, vi8, vi9, via;
|
||||
|
||||
void test (void)
|
||||
{
|
||||
vi0 = 0;
|
||||
printf ("hello");
|
||||
vi1 = 0;
|
||||
printf ("hello\n");
|
||||
vi2 = 0;
|
||||
printf ("a");
|
||||
vi3 = 0;
|
||||
printf ("");
|
||||
vi4 = 0;
|
||||
printf ("%s", "hello");
|
||||
vi5 = 0;
|
||||
printf ("%s", "hello\n");
|
||||
vi6 = 0;
|
||||
printf ("%s", "a");
|
||||
vi7 = 0;
|
||||
printf ("%s", "");
|
||||
vi8 = 0;
|
||||
printf ("%c", 'x');
|
||||
vi9 = 0;
|
||||
printf ("%s\n", "hello\n");
|
||||
via = 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump "vi0.*printf.*\"hello\".*vi1" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi1.*puts.*\"hello\".*vi2" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi2.*putchar.*vi3" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi3 = 0\[^\(\)\]*vi4 = 0" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi4.*printf.*\"hello\".*vi5" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi5.*puts.*\"hello\".*vi6" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi6.*putchar.*vi7" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi7 = 0\[^\(\)\]*vi8 = 0" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi8.*putchar.*vi9" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi9.*puts.*\"hello\\\\n\".*via" "fab"} } */
|
41
gcc/testsuite/gcc.dg/tree-ssa/builtin-printf-chk-1.c
Normal file
41
gcc/testsuite/gcc.dg/tree-ssa/builtin-printf-chk-1.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-fab" } */
|
||||
|
||||
extern int __printf_chk (int, const char *, ...);
|
||||
volatile int vi0, vi1, vi2, vi3, vi4, vi5, vi6, vi7, vi8, vi9, via;
|
||||
|
||||
void test (void)
|
||||
{
|
||||
vi0 = 0;
|
||||
__printf_chk (1, "hello");
|
||||
vi1 = 0;
|
||||
__printf_chk (1, "hello\n");
|
||||
vi2 = 0;
|
||||
__printf_chk (1, "a");
|
||||
vi3 = 0;
|
||||
__printf_chk (1, "");
|
||||
vi4 = 0;
|
||||
__printf_chk (1, "%s", "hello");
|
||||
vi5 = 0;
|
||||
__printf_chk (1, "%s", "hello\n");
|
||||
vi6 = 0;
|
||||
__printf_chk (1, "%s", "a");
|
||||
vi7 = 0;
|
||||
__printf_chk (1, "%s", "");
|
||||
vi8 = 0;
|
||||
__printf_chk (1, "%c", 'x');
|
||||
vi9 = 0;
|
||||
__printf_chk (1, "%s\n", "hello\n");
|
||||
via = 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump "vi0.*__printf_chk.*1.*\"hello\".*vi1" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi1.*puts.*\"hello\".*vi2" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi2.*putchar.*vi3" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi3 = 0\[^\(\)\]*vi4 = 0" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi4.*__printf_chk.*1.*\"hello\".*vi5" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi5.*puts.*\"hello\".*vi6" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi6.*putchar.*vi7" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi7 = 0\[^\(\)\]*vi8 = 0" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi8.*putchar.*vi9" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi9.*puts.*\"hello\\\\n\".*via" "fab"} } */
|
38
gcc/testsuite/gcc.dg/tree-ssa/builtin-vfprintf-1.c
Normal file
38
gcc/testsuite/gcc.dg/tree-ssa/builtin-vfprintf-1.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-fab" } */
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
typedef struct { int i; } FILE;
|
||||
FILE *fp;
|
||||
extern int vfprintf (FILE *, const char *, va_list);
|
||||
volatile int vi0, vi1, vi2, vi3, vi4, vi5, vi6, vi7, vi8, vi9, via;
|
||||
|
||||
void
|
||||
test (va_list ap1, va_list ap2, va_list ap3, va_list ap4, va_list ap5,
|
||||
va_list ap6, va_list ap7)
|
||||
{
|
||||
vi0 = 0;
|
||||
vfprintf (fp, "hello", ap1);
|
||||
vi1 = 0;
|
||||
vfprintf (fp, "hello\n", ap2);
|
||||
vi2 = 0;
|
||||
vfprintf (fp, "a", ap3);
|
||||
vi3 = 0;
|
||||
vfprintf (fp, "", ap4);
|
||||
vi4 = 0;
|
||||
vfprintf (fp, "%s", ap5);
|
||||
vi5 = 0;
|
||||
vfprintf (fp, "%c", ap6);
|
||||
vi6 = 0;
|
||||
vfprintf (fp, "%s\n", ap7);
|
||||
vi7 = 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump "vi0.*fwrite.*\"hello\".*1, 5, fp.*vi1" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi1.*fwrite.*\"hello\\\\n\".*1, 6, fp.*vi2" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi2.*fputc.*fp.*vi3" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi3 = 0\[^\(\)\]*vi4 = 0" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi4.*vfprintf.*\"%s\".*vi5" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi5.*vfprintf.*\"%c\".*vi6" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi6.*vfprintf.*\"%s\\\\n\".*vi7" "fab"} } */
|
38
gcc/testsuite/gcc.dg/tree-ssa/builtin-vfprintf-chk-1.c
Normal file
38
gcc/testsuite/gcc.dg/tree-ssa/builtin-vfprintf-chk-1.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-fab" } */
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
typedef struct { int i; } FILE;
|
||||
FILE *fp;
|
||||
extern int __vfprintf_chk (FILE *, int, const char *, va_list);
|
||||
volatile int vi0, vi1, vi2, vi3, vi4, vi5, vi6, vi7, vi8, vi9, via;
|
||||
|
||||
void
|
||||
test (va_list ap1, va_list ap2, va_list ap3, va_list ap4, va_list ap5,
|
||||
va_list ap6, va_list ap7)
|
||||
{
|
||||
vi0 = 0;
|
||||
__vfprintf_chk (fp, 1, "hello", ap1);
|
||||
vi1 = 0;
|
||||
__vfprintf_chk (fp, 1, "hello\n", ap2);
|
||||
vi2 = 0;
|
||||
__vfprintf_chk (fp, 1, "a", ap3);
|
||||
vi3 = 0;
|
||||
__vfprintf_chk (fp, 1, "", ap4);
|
||||
vi4 = 0;
|
||||
__vfprintf_chk (fp, 1, "%s", ap5);
|
||||
vi5 = 0;
|
||||
__vfprintf_chk (fp, 1, "%c", ap6);
|
||||
vi6 = 0;
|
||||
__vfprintf_chk (fp, 1, "%s\n", ap7);
|
||||
vi7 = 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump "vi0.*fwrite.*\"hello\".*1, 5, fp.*vi1" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi1.*fwrite.*\"hello\\\\n\".*1, 6, fp.*vi2" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi2.*fputc.*fp.*vi3" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi3 = 0\[^\(\)\]*vi4 = 0" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi4.*__vfprintf_chk.*fp.*1.*\"%s\".*vi5" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi5.*__vfprintf_chk.*fp.*1.*\"%c\".*vi6" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi6.*__vfprintf_chk.*fp.*1.*\"%s\\\\n\".*vi7" "fab"} } */
|
36
gcc/testsuite/gcc.dg/tree-ssa/builtin-vprintf-1.c
Normal file
36
gcc/testsuite/gcc.dg/tree-ssa/builtin-vprintf-1.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-fab" } */
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
extern int vprintf (const char *, va_list);
|
||||
volatile int vi0, vi1, vi2, vi3, vi4, vi5, vi6, vi7, vi8, vi9, via;
|
||||
|
||||
void
|
||||
test (va_list ap1, va_list ap2, va_list ap3, va_list ap4, va_list ap5,
|
||||
va_list ap6, va_list ap7)
|
||||
{
|
||||
vi0 = 0;
|
||||
vprintf ("hello", ap1);
|
||||
vi1 = 0;
|
||||
vprintf ("hello\n", ap2);
|
||||
vi2 = 0;
|
||||
vprintf ("a", ap3);
|
||||
vi3 = 0;
|
||||
vprintf ("", ap4);
|
||||
vi4 = 0;
|
||||
vprintf ("%s", ap5);
|
||||
vi5 = 0;
|
||||
vprintf ("%c", ap6);
|
||||
vi6 = 0;
|
||||
vprintf ("%s\n", ap7);
|
||||
vi7 = 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump "vi0.*vprintf.*\"hello\".*vi1" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi1.*puts.*\"hello\".*vi2" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi2.*putchar.*vi3" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi3 = 0\[^\(\)\]*vi4 = 0" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi4.*vprintf.*\"%s\".*vi5" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi5.*vprintf.*\"%c\".*vi6" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi6.*vprintf.*\"%s\\\\n\".*vi7" "fab"} } */
|
36
gcc/testsuite/gcc.dg/tree-ssa/builtin-vprintf-chk-1.c
Normal file
36
gcc/testsuite/gcc.dg/tree-ssa/builtin-vprintf-chk-1.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-fab" } */
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
extern int __vprintf_chk (int, const char *, va_list);
|
||||
volatile int vi0, vi1, vi2, vi3, vi4, vi5, vi6, vi7, vi8, vi9, via;
|
||||
|
||||
void
|
||||
test (va_list ap1, va_list ap2, va_list ap3, va_list ap4, va_list ap5,
|
||||
va_list ap6, va_list ap7)
|
||||
{
|
||||
vi0 = 0;
|
||||
__vprintf_chk (1, "hello", ap1);
|
||||
vi1 = 0;
|
||||
__vprintf_chk (1, "hello\n", ap2);
|
||||
vi2 = 0;
|
||||
__vprintf_chk (1, "a", ap3);
|
||||
vi3 = 0;
|
||||
__vprintf_chk (1, "", ap4);
|
||||
vi4 = 0;
|
||||
__vprintf_chk (1, "%s", ap5);
|
||||
vi5 = 0;
|
||||
__vprintf_chk (1, "%c", ap6);
|
||||
vi6 = 0;
|
||||
__vprintf_chk (1, "%s\n", ap7);
|
||||
vi7 = 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump "vi0.*__vprintf_chk.*1.*\"hello\".*vi1" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi1.*puts.*\"hello\".*vi2" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi2.*putchar.*vi3" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi3 = 0\[^\(\)\]*vi4 = 0" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi4.*__vprintf_chk.*1.*\"%s\".*vi5" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi5.*__vprintf_chk.*1.*\"%c\".*vi6" "fab"} } */
|
||||
/* { dg-final { scan-tree-dump "vi6.*__vprintf_chk.*1.*\"%s\\\\n\".*vi7" "fab"} } */
|
1078
gcc/tree-object-size.c
Normal file
1078
gcc/tree-object-size.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -435,6 +435,7 @@ init_tree_optimization_passes (void)
|
|||
NEXT_PASS (pass_may_alias);
|
||||
NEXT_PASS (pass_forwprop);
|
||||
NEXT_PASS (pass_phiopt);
|
||||
NEXT_PASS (pass_object_sizes);
|
||||
NEXT_PASS (pass_store_ccp);
|
||||
NEXT_PASS (pass_store_copy_prop);
|
||||
NEXT_PASS (pass_fold_builtins);
|
||||
|
|
|
@ -196,6 +196,7 @@ extern struct tree_opt_pass pass_lower_complex_O0;
|
|||
extern struct tree_opt_pass pass_lower_complex;
|
||||
extern struct tree_opt_pass pass_lower_vector;
|
||||
extern struct tree_opt_pass pass_lower_vector_ssa;
|
||||
extern struct tree_opt_pass pass_object_sizes;
|
||||
extern struct tree_opt_pass pass_fold_builtins;
|
||||
extern struct tree_opt_pass pass_stdarg;
|
||||
extern struct tree_opt_pass pass_early_warn_uninitialized;
|
||||
|
|
|
@ -1965,25 +1965,50 @@ fold_stmt_r (tree *expr_p, int *walk_subtrees, void *data)
|
|||
}
|
||||
|
||||
|
||||
/* Return the string length of ARG in LENGTH. If ARG is an SSA name variable,
|
||||
follow its use-def chains. If LENGTH is not NULL and its value is not
|
||||
equal to the length we determine, or if we are unable to determine the
|
||||
length, return false. VISITED is a bitmap of visited variables. */
|
||||
/* Return the string length, maximum string length or maximum value of
|
||||
ARG in LENGTH.
|
||||
If ARG is an SSA name variable, follow its use-def chains. If LENGTH
|
||||
is not NULL and, for TYPE == 0, its value is not equal to the length
|
||||
we determine or if we are unable to determine the length or value,
|
||||
return false. VISITED is a bitmap of visited variables.
|
||||
TYPE is 0 if string length should be returned, 1 for maximum string
|
||||
length and 2 for maximum value ARG can have. */
|
||||
|
||||
static bool
|
||||
get_strlen (tree arg, tree *length, bitmap visited)
|
||||
get_maxval_strlen (tree arg, tree *length, bitmap visited, int type)
|
||||
{
|
||||
tree var, def_stmt, val;
|
||||
|
||||
if (TREE_CODE (arg) != SSA_NAME)
|
||||
{
|
||||
if (type == 2)
|
||||
{
|
||||
val = arg;
|
||||
if (TREE_CODE (val) != INTEGER_CST
|
||||
|| tree_int_cst_sgn (val) < 0)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
val = c_strlen (arg, 1);
|
||||
if (!val)
|
||||
return false;
|
||||
|
||||
if (*length && simple_cst_equal (val, *length) != 1)
|
||||
if (*length)
|
||||
{
|
||||
if (type > 0)
|
||||
{
|
||||
if (TREE_CODE (*length) != INTEGER_CST
|
||||
|| TREE_CODE (val) != INTEGER_CST)
|
||||
return false;
|
||||
|
||||
if (tree_int_cst_lt (*length, val))
|
||||
*length = val;
|
||||
return true;
|
||||
}
|
||||
else if (simple_cst_equal (val, *length) != 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
*length = val;
|
||||
return true;
|
||||
}
|
||||
|
@ -2000,28 +2025,14 @@ get_strlen (tree arg, tree *length, bitmap visited)
|
|||
{
|
||||
case MODIFY_EXPR:
|
||||
{
|
||||
tree len, rhs;
|
||||
tree rhs;
|
||||
|
||||
/* The RHS of the statement defining VAR must either have a
|
||||
constant length or come from another SSA_NAME with a constant
|
||||
length. */
|
||||
rhs = TREE_OPERAND (def_stmt, 1);
|
||||
STRIP_NOPS (rhs);
|
||||
if (TREE_CODE (rhs) == SSA_NAME)
|
||||
return get_strlen (rhs, length, visited);
|
||||
|
||||
/* See if the RHS is a constant length. */
|
||||
len = c_strlen (rhs, 1);
|
||||
if (len)
|
||||
{
|
||||
if (*length && simple_cst_equal (len, *length) != 1)
|
||||
return false;
|
||||
|
||||
*length = len;
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
return get_maxval_strlen (rhs, length, visited, type);
|
||||
}
|
||||
|
||||
case PHI_NODE:
|
||||
|
@ -2043,7 +2054,7 @@ get_strlen (tree arg, tree *length, bitmap visited)
|
|||
if (arg == PHI_RESULT (def_stmt))
|
||||
continue;
|
||||
|
||||
if (!get_strlen (arg, length, visited))
|
||||
if (!get_maxval_strlen (arg, length, visited, type))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2065,9 +2076,9 @@ get_strlen (tree arg, tree *length, bitmap visited)
|
|||
static tree
|
||||
ccp_fold_builtin (tree stmt, tree fn)
|
||||
{
|
||||
tree result, strlen_val[2];
|
||||
tree result, val[3];
|
||||
tree callee, arglist, a;
|
||||
int strlen_arg, i;
|
||||
int arg_mask, i, type;
|
||||
bitmap visited;
|
||||
bool ignore;
|
||||
|
||||
|
@ -2100,11 +2111,31 @@ ccp_fold_builtin (tree stmt, tree fn)
|
|||
case BUILT_IN_STRLEN:
|
||||
case BUILT_IN_FPUTS:
|
||||
case BUILT_IN_FPUTS_UNLOCKED:
|
||||
strlen_arg = 1;
|
||||
arg_mask = 1;
|
||||
type = 0;
|
||||
break;
|
||||
case BUILT_IN_STRCPY:
|
||||
case BUILT_IN_STRNCPY:
|
||||
strlen_arg = 2;
|
||||
arg_mask = 2;
|
||||
type = 0;
|
||||
break;
|
||||
case BUILT_IN_MEMCPY_CHK:
|
||||
case BUILT_IN_MEMPCPY_CHK:
|
||||
case BUILT_IN_MEMMOVE_CHK:
|
||||
case BUILT_IN_MEMSET_CHK:
|
||||
case BUILT_IN_STRNCPY_CHK:
|
||||
arg_mask = 4;
|
||||
type = 2;
|
||||
break;
|
||||
case BUILT_IN_STRCPY_CHK:
|
||||
case BUILT_IN_STPCPY_CHK:
|
||||
arg_mask = 2;
|
||||
type = 1;
|
||||
break;
|
||||
case BUILT_IN_SNPRINTF_CHK:
|
||||
case BUILT_IN_VSNPRINTF_CHK:
|
||||
arg_mask = 2;
|
||||
type = 2;
|
||||
break;
|
||||
default:
|
||||
return NULL_TREE;
|
||||
|
@ -2113,15 +2144,15 @@ ccp_fold_builtin (tree stmt, tree fn)
|
|||
/* Try to use the dataflow information gathered by the CCP process. */
|
||||
visited = BITMAP_ALLOC (NULL);
|
||||
|
||||
memset (strlen_val, 0, sizeof (strlen_val));
|
||||
memset (val, 0, sizeof (val));
|
||||
for (i = 0, a = arglist;
|
||||
strlen_arg;
|
||||
i++, strlen_arg >>= 1, a = TREE_CHAIN (a))
|
||||
if (strlen_arg & 1)
|
||||
arg_mask;
|
||||
i++, arg_mask >>= 1, a = TREE_CHAIN (a))
|
||||
if (arg_mask & 1)
|
||||
{
|
||||
bitmap_clear (visited);
|
||||
if (!get_strlen (TREE_VALUE (a), &strlen_val[i], visited))
|
||||
strlen_val[i] = NULL_TREE;
|
||||
if (!get_maxval_strlen (TREE_VALUE (a), &val[i], visited, type))
|
||||
val[i] = NULL_TREE;
|
||||
}
|
||||
|
||||
BITMAP_FREE (visited);
|
||||
|
@ -2130,9 +2161,9 @@ ccp_fold_builtin (tree stmt, tree fn)
|
|||
switch (DECL_FUNCTION_CODE (callee))
|
||||
{
|
||||
case BUILT_IN_STRLEN:
|
||||
if (strlen_val[0])
|
||||
if (val[0])
|
||||
{
|
||||
tree new = fold_convert (TREE_TYPE (fn), strlen_val[0]);
|
||||
tree new = fold_convert (TREE_TYPE (fn), val[0]);
|
||||
|
||||
/* If the result is not a valid gimple value, or not a cast
|
||||
of a valid gimple value, then we can not use the result. */
|
||||
|
@ -2144,33 +2175,53 @@ ccp_fold_builtin (tree stmt, tree fn)
|
|||
break;
|
||||
|
||||
case BUILT_IN_STRCPY:
|
||||
if (strlen_val[1] && is_gimple_val (strlen_val[1]))
|
||||
{
|
||||
tree fndecl = get_callee_fndecl (fn);
|
||||
tree arglist = TREE_OPERAND (fn, 1);
|
||||
result = fold_builtin_strcpy (fndecl, arglist, strlen_val[1]);
|
||||
}
|
||||
if (val[1] && is_gimple_val (val[1]))
|
||||
result = fold_builtin_strcpy (callee, arglist, val[1]);
|
||||
break;
|
||||
|
||||
case BUILT_IN_STRNCPY:
|
||||
if (strlen_val[1] && is_gimple_val (strlen_val[1]))
|
||||
{
|
||||
tree fndecl = get_callee_fndecl (fn);
|
||||
tree arglist = TREE_OPERAND (fn, 1);
|
||||
result = fold_builtin_strncpy (fndecl, arglist, strlen_val[1]);
|
||||
}
|
||||
if (val[1] && is_gimple_val (val[1]))
|
||||
result = fold_builtin_strncpy (callee, arglist, val[1]);
|
||||
break;
|
||||
|
||||
case BUILT_IN_FPUTS:
|
||||
result = fold_builtin_fputs (arglist,
|
||||
TREE_CODE (stmt) != MODIFY_EXPR, 0,
|
||||
strlen_val[0]);
|
||||
val[0]);
|
||||
break;
|
||||
|
||||
case BUILT_IN_FPUTS_UNLOCKED:
|
||||
result = fold_builtin_fputs (arglist,
|
||||
TREE_CODE (stmt) != MODIFY_EXPR, 1,
|
||||
strlen_val[0]);
|
||||
val[0]);
|
||||
break;
|
||||
|
||||
case BUILT_IN_MEMCPY_CHK:
|
||||
case BUILT_IN_MEMPCPY_CHK:
|
||||
case BUILT_IN_MEMMOVE_CHK:
|
||||
case BUILT_IN_MEMSET_CHK:
|
||||
if (val[2] && is_gimple_val (val[2]))
|
||||
result = fold_builtin_memory_chk (callee, arglist, val[2], ignore,
|
||||
DECL_FUNCTION_CODE (callee));
|
||||
break;
|
||||
|
||||
case BUILT_IN_STRCPY_CHK:
|
||||
case BUILT_IN_STPCPY_CHK:
|
||||
if (val[1] && is_gimple_val (val[1]))
|
||||
result = fold_builtin_stxcpy_chk (callee, arglist, val[1], ignore,
|
||||
DECL_FUNCTION_CODE (callee));
|
||||
break;
|
||||
|
||||
case BUILT_IN_STRNCPY_CHK:
|
||||
if (val[2] && is_gimple_val (val[2]))
|
||||
result = fold_builtin_strncpy_chk (arglist, val[2]);
|
||||
break;
|
||||
|
||||
case BUILT_IN_SNPRINTF_CHK:
|
||||
case BUILT_IN_VSNPRINTF_CHK:
|
||||
if (val[1] && is_gimple_val (val[1]))
|
||||
result = fold_builtin_snprintf_chk (arglist, val[1],
|
||||
DECL_FUNCTION_CODE (callee));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -2338,18 +2389,26 @@ execute_fold_all_builtins (void)
|
|||
FOR_EACH_BB (bb)
|
||||
{
|
||||
block_stmt_iterator i;
|
||||
for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
|
||||
for (i = bsi_start (bb); !bsi_end_p (i); )
|
||||
{
|
||||
tree *stmtp = bsi_stmt_ptr (i);
|
||||
tree old_stmt = *stmtp;
|
||||
tree call = get_rhs (*stmtp);
|
||||
tree callee, result;
|
||||
enum built_in_function fcode;
|
||||
|
||||
if (!call || TREE_CODE (call) != CALL_EXPR)
|
||||
{
|
||||
bsi_next (&i);
|
||||
continue;
|
||||
}
|
||||
callee = get_callee_fndecl (call);
|
||||
if (!callee || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL)
|
||||
{
|
||||
bsi_next (&i);
|
||||
continue;
|
||||
}
|
||||
fcode = DECL_FUNCTION_CODE (callee);
|
||||
|
||||
result = ccp_fold_builtin (*stmtp, call);
|
||||
if (!result)
|
||||
|
@ -2363,6 +2422,7 @@ execute_fold_all_builtins (void)
|
|||
break;
|
||||
|
||||
default:
|
||||
bsi_next (&i);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2393,6 +2453,20 @@ execute_fold_all_builtins (void)
|
|||
print_generic_stmt (dump_file, *stmtp, dump_flags);
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
|
||||
/* Retry the same statement if it changed into another
|
||||
builtin, there might be new opportunities now. */
|
||||
call = get_rhs (*stmtp);
|
||||
if (!call || TREE_CODE (call) != CALL_EXPR)
|
||||
{
|
||||
bsi_next (&i);
|
||||
continue;
|
||||
}
|
||||
callee = get_callee_fndecl (call);
|
||||
if (!callee
|
||||
|| DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL
|
||||
|| DECL_FUNCTION_CODE (callee) == fcode)
|
||||
bsi_next (&i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
11
gcc/tree.h
11
gcc/tree.h
|
@ -3623,6 +3623,12 @@ extern tree fold_builtin (tree, tree, bool);
|
|||
extern tree fold_builtin_fputs (tree, bool, bool, tree);
|
||||
extern tree fold_builtin_strcpy (tree, tree, tree);
|
||||
extern tree fold_builtin_strncpy (tree, tree, tree);
|
||||
extern tree fold_builtin_memory_chk (tree, tree, tree, bool,
|
||||
enum built_in_function);
|
||||
extern tree fold_builtin_stxcpy_chk (tree, tree, tree, bool,
|
||||
enum built_in_function);
|
||||
extern tree fold_builtin_strncpy_chk (tree, tree);
|
||||
extern tree fold_builtin_snprintf_chk (tree, tree, enum built_in_function);
|
||||
extern bool fold_builtin_next_arg (tree);
|
||||
extern enum built_in_function builtin_mathfn_code (tree);
|
||||
extern tree build_function_call_expr (tree, tree);
|
||||
|
@ -4010,4 +4016,9 @@ extern void vect_set_verbosity_level (const char *);
|
|||
extern tree tree_mem_ref_addr (tree, tree);
|
||||
extern void copy_mem_ref_info (tree, tree);
|
||||
|
||||
/* In tree-object-size.c. */
|
||||
extern void init_object_sizes (void);
|
||||
extern void fini_object_sizes (void);
|
||||
extern unsigned HOST_WIDE_INT compute_builtin_object_size (tree, int);
|
||||
|
||||
#endif /* GCC_TREE_H */
|
||||
|
|
Loading…
Add table
Reference in a new issue