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:
Jakub Jelinek 2005-06-27 14:17:39 +02:00 committed by Jakub Jelinek
parent de16a5b6a4
commit 10a0d49571
67 changed files with 10572 additions and 66 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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,

File diff suppressed because it is too large Load Diff

View File

@ -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")

View File

@ -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 ();

View File

@ -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

View File

@ -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

View 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;

View 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;
}

View File

@ -1,5 +1,6 @@
extern void abort(void);
extern void main_test (void);
extern void abort (void);
int inside_main;
int

View File

@ -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--;
}

View File

@ -0,0 +1 @@
#include "lib/chk.c"

View 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 ();
}

View File

@ -0,0 +1 @@
#include "lib/chk.c"

View 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 ();
}

View File

@ -0,0 +1 @@
#include "lib/chk.c"

View 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 ();
}

View File

@ -0,0 +1 @@
#include "lib/chk.c"

View 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 ();
}

View File

@ -0,0 +1 @@
#include "lib/chk.c"

View 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 ();
}

View File

@ -0,0 +1 @@
#include "lib/chk.c"

View 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 ();
}

View File

@ -0,0 +1 @@
#include "lib/chk.c"

View 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 ();
}

View File

@ -0,0 +1 @@
#include "lib/chk.c"

View 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 ();
}

View File

@ -0,0 +1 @@
#include "lib/chk.c"

View 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 ();
}

View File

@ -0,0 +1 @@
#include "lib/chk.c"

View 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 ();
}

View File

@ -0,0 +1 @@
#include "lib/chk.c"

View 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 ();
}

View File

@ -0,0 +1 @@
#include "lib/chk.c"

View 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 ();
}

View File

@ -0,0 +1 @@
#include "lib/chk.c"

View 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 ();
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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

View 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

View 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

View 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

View 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);
}

View 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);
}

View 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);
}

View 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);
}

View 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" } } */

View 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" } */
}

View 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;
}

View 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"} } */

View 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"} } */

View 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"} } */

View 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"} } */

View 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"} } */

View 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"} } */

View 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"} } */

View 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

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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;

View File

@ -1965,24 +1965,49 @@ 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)
{
val = c_strlen (arg, 1);
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)
return false;
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;
@ -2079,11 +2090,11 @@ ccp_fold_builtin (tree stmt, tree fn)
arglist = TREE_OPERAND (fn, 1);
result = fold_builtin (callee, arglist, ignore);
if (result)
{
if (ignore)
STRIP_NOPS (result);
return result;
}
{
if (ignore)
STRIP_NOPS (result);
return result;
}
/* Ignore MD builtins. */
if (DECL_BUILT_IN_CLASS (callee) == BUILT_IN_MD)
@ -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)
continue;
{
bsi_next (&i);
continue;
}
callee = get_callee_fndecl (call);
if (!callee || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL)
continue;
{
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);
}
}

View File

@ -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 */