From 254986c7ff3175c29307b999f161cfcc7961baf4 Mon Sep 17 00:00:00 2001 From: "Kaveh R. Ghazi" Date: Sun, 5 Sep 2004 02:55:28 +0000 Subject: [PATCH] builtin-attrs.def (ATTR_NOTHROW_SENTINEL_1): New. * builtin-attrs.def (ATTR_NOTHROW_SENTINEL_1): New. * builtins.def (BUILT_IN_EXECLE): Set ATTR_NOTHROW_SENTINEL_1. * c-common.c (c_common_attribute_table): Accept parameters to sentinel attribute. (check_function_sentinel, handle_sentinel_attribute): Likewise. * doc/extend.texi: Update accordingly. testsuite: * gcc.dg/format/sentinel-1.c: Update for parameter option. From-SVN: r87098 --- gcc/ChangeLog | 9 +++ gcc/builtin-attrs.def | 2 + gcc/builtins.def | 2 +- gcc/c-common.c | 84 +++++++++++++++++++----- gcc/doc/extend.texi | 33 +++++++--- gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/gcc.dg/format/sentinel-1.c | 29 ++++++++ 7 files changed, 136 insertions(+), 27 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 96da912b162..88486b14796 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2004-09-04 Kaveh R. Ghazi + + * builtin-attrs.def (ATTR_NOTHROW_SENTINEL_1): New. + * builtins.def (BUILT_IN_EXECLE): Set ATTR_NOTHROW_SENTINEL_1. + * c-common.c (c_common_attribute_table): Accept parameters to + sentinel attribute. + (check_function_sentinel, handle_sentinel_attribute): Likewise. + * doc/extend.texi: Update accordingly. + 2004-09-04 Kaveh R. Ghazi * builtin-attrs.def (ATTR_SENTINEL, ATTR_SENTINEL_NOTHROW_LIST): diff --git a/gcc/builtin-attrs.def b/gcc/builtin-attrs.def index 67cf193e4fd..f376f5571b5 100644 --- a/gcc/builtin-attrs.def +++ b/gcc/builtin-attrs.def @@ -101,6 +101,8 @@ DEF_ATTR_TREE_LIST (ATTR_MALLOC_NOTHROW_LIST, ATTR_MALLOC, \ DEF_ATTR_TREE_LIST (ATTR_SENTINEL_NOTHROW_LIST, ATTR_SENTINEL, \ ATTR_NULL, ATTR_NOTHROW_LIST) +DEF_ATTR_TREE_LIST (ATTR_NOTHROW_SENTINEL_1, ATTR_SENTINEL, ATTR_LIST_1, \ + ATTR_NOTHROW_LIST) DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_1, ATTR_NONNULL, ATTR_LIST_1, \ ATTR_NOTHROW_LIST) DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_2, ATTR_NONNULL, ATTR_LIST_2, \ diff --git a/gcc/builtins.def b/gcc/builtins.def index e89509fcebf..1bdc8aa79ee 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -556,7 +556,7 @@ DEF_GCC_BUILTIN (BUILT_IN_EH_RETURN, "eh_return", BT_FN_VOID_PTRMODE_PTR, DEF_GCC_BUILTIN (BUILT_IN_EH_RETURN_DATA_REGNO, "eh_return_data_regno", BT_FN_INT_INT, ATTR_NULL) DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECL, "execl", BT_FN_INT_CONST_STRING_CONST_STRING_VAR, ATTR_SENTINEL_NOTHROW_LIST) DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECLP, "execlp", BT_FN_INT_CONST_STRING_CONST_STRING_VAR, ATTR_SENTINEL_NOTHROW_LIST) -DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECLE, "execle", BT_FN_INT_CONST_STRING_CONST_STRING_VAR, ATTR_NOTHROW_LIST) +DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECLE, "execle", BT_FN_INT_CONST_STRING_CONST_STRING_VAR, ATTR_NOTHROW_SENTINEL_1) DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECV, "execv", BT_FN_INT_CONST_STRING_PTR_CONST_STRING, ATTR_NOTHROW_LIST) DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECVP, "execvp", BT_FN_INT_CONST_STRING_PTR_CONST_STRING, ATTR_NOTHROW_LIST) DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECVE, "execve", BT_FN_INT_CONST_STRING_PTR_CONST_STRING_PTR_CONST_STRING, ATTR_NOTHROW_LIST) diff --git a/gcc/c-common.c b/gcc/c-common.c index 3af1e6408ed..1a105701eb0 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -636,7 +636,7 @@ const struct attribute_spec c_common_attribute_table[] = handle_cleanup_attribute }, { "warn_unused_result", 0, 0, false, true, true, handle_warn_unused_result_attribute }, - { "sentinel", 0, 0, false, true, true, + { "sentinel", 0, 1, false, true, true, handle_sentinel_attribute }, { NULL, 0, 0, false, false, false, NULL } }; @@ -5047,7 +5047,8 @@ check_function_nonnull (tree attrs, tree params) } } -/* Check the last argument of a function call is (pointer)0. */ +/* Check that the Nth argument of a function call (counting backwards + from the end) is a (pointer)0. */ static void check_function_sentinel (tree attrs, tree params) @@ -5060,11 +5061,40 @@ check_function_sentinel (tree attrs, tree params) warning ("missing sentinel in function call"); else { - /* Find the last parameter. */ - while (TREE_CHAIN (params)) - params = TREE_CHAIN (params); - if (!POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (params))) - || !integer_zerop (TREE_VALUE (params))) + tree sentinel, end; + unsigned pos = 0; + + if (TREE_VALUE (attr)) + { + tree p = TREE_VALUE (TREE_VALUE (attr)); + STRIP_NOPS (p); + pos = TREE_INT_CST_LOW (p); + } + + sentinel = end = params; + + /* Advance `end' ahead of `sentinel' by `pos' positions. */ + while (pos > 0 && TREE_CHAIN (end)) + { + pos--; + end = TREE_CHAIN (end); + } + if (pos > 0) + { + warning ("not enough arguments to fit a sentinel"); + return; + } + + /* Now advance both until we find the last parameter. */ + while (TREE_CHAIN (end)) + { + end = TREE_CHAIN (end); + sentinel = TREE_CHAIN (sentinel); + } + + /* Validate the sentinel. */ + if (!POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (sentinel))) + || !integer_zerop (TREE_VALUE (sentinel))) warning ("missing sentinel in function call"); } } @@ -5215,8 +5245,7 @@ handle_warn_unused_result_attribute (tree *node, tree name, /* Handle a "sentinel" attribute. */ static tree -handle_sentinel_attribute (tree *node, tree name, - tree ARG_UNUSED (args), +handle_sentinel_attribute (tree *node, tree name, tree args, int ARG_UNUSED (flags), bool *no_add_attrs) { tree params = TYPE_ARG_TYPES (*node); @@ -5226,17 +5255,38 @@ handle_sentinel_attribute (tree *node, tree name, warning ("`%s' attribute requires prototypes with named arguments", IDENTIFIER_POINTER (name)); *no_add_attrs = true; - return NULL_TREE; } + else + { + while (TREE_CHAIN (params)) + params = TREE_CHAIN (params); - while (TREE_CHAIN (params)) - params = TREE_CHAIN (params); - - if (VOID_TYPE_P (TREE_VALUE (params))) + if (VOID_TYPE_P (TREE_VALUE (params))) + { + warning ("`%s' attribute only applies to variadic functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + } + + if (args) { - warning ("`%s' attribute only applies to variadic functions", - IDENTIFIER_POINTER (name)); - *no_add_attrs = true; + tree position = TREE_VALUE (args); + + STRIP_NOPS (position); + if (TREE_CODE (position) != INTEGER_CST) + { + warning ("requested position is not an integer constant"); + *no_add_attrs = true; + } + else + { + if (tree_int_cst_lt (position, integer_zero_node)) + { + warning ("requested position is less than zero"); + *no_add_attrs = true; + } + } } return NULL_TREE; diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 4c27320f2b9..bbde788ee5c 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2113,15 +2113,30 @@ section, consider using the facilities of the linker instead. @item sentinel @cindex @code{sentinel} function attribute -This function attribute ensures that the last parameter in a function -call is an explicit @code{NULL}. The attribute is only valid on -variadic functions. For example the attribute is automatically set for -the built-in functions @code{execl} and @code{execlp} where @code{NULL} -is the marker for argument list termination. A valid @code{NULL} in -this context is defined as zero with any pointer type. If your system -defines the @code{NULL} macro with an integer type then you need to add -an explicit cast. The warnings for missing or incorrect sentinels are -enabled with @option{-Wformat}. +This function attribute ensures that a parameter in a function call is +an explicit @code{NULL}. The attribute is only valid on variadic +functions. By default, the sentinel is located at position zero, the +last parameter of the function call. If an optional integer position +argument P is supplied to the attribute, the sentinel must be located at +position P counting backwards from the end of the argument list. + +@smallexample +__attribute__ ((sentinel)) +is equivalent to +__attribute__ ((sentinel(0))) +@end smallexample + +The attribute is automatically set with a position of 0 for the built-in +functions @code{execl} and @code{execlp}. The built-in function +@code{execle} has the attribute set set with a position of 1. + +A valid @code{NULL} in this context is defined as zero with any pointer +type. If your system defines the @code{NULL} macro with an integer type +then you need to add an explicit cast. GCC replaces @code{stddef.h} +with a copy that redefines NULL appropriately. + +The warnings for missing or incorrect sentinels are enabled with +@option{-Wformat}. @item short_call See long_call/short_call. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4fb58cb251b..01e0815f462 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2004-09-04 Kaveh R. Ghazi + + * gcc.dg/format/sentinel-1.c: Update for parameter option. + 2004-09-04 Kaveh R. Ghazi * gcc.dg/format/sentinel-1.c: New test. diff --git a/gcc/testsuite/gcc.dg/format/sentinel-1.c b/gcc/testsuite/gcc.dg/format/sentinel-1.c index e1e127dca38..12915b7dc5a 100644 --- a/gcc/testsuite/gcc.dg/format/sentinel-1.c +++ b/gcc/testsuite/gcc.dg/format/sentinel-1.c @@ -7,6 +7,8 @@ extern int execl (const char *, const char *, ...); extern int execlp (const char *, const char *, ...); +extern int execle (const char *, const char *, ...); +extern char *envp[]; #define ATTR __attribute__ ((__sentinel__)) @@ -16,6 +18,12 @@ extern void foo1 (const char *, ...) ATTR; extern void foo2 (...) ATTR; /* { dg-error "ISO C requires|named arguments" "sentinel" } */ extern void foo3 () ATTR; /* { dg-warning "named arguments" "sentinel" } */ extern void foo4 (const char *, int) ATTR; /* { dg-warning "variadic functions" "sentinel" } */ +extern void foo5 (const char *, ...) __attribute__ ((__sentinel__(1))); +extern void foo6 (const char *, ...) __attribute__ ((__sentinel__(5))); +extern void foo7 (const char *, ...) __attribute__ ((__sentinel__(0))); +extern void foo8 (const char *, ...) __attribute__ ((__sentinel__("a"))); /* { dg-warning "not an integer constant" "sentinel" } */ +extern void foo9 (const char *, ...) __attribute__ ((__sentinel__(-1))); /* { dg-warning "less than zero" "sentinel" } */ +extern void foo10 (const char *, ...) __attribute__ ((__sentinel__(1,3))); /* { dg-error "wrong number of arguments" "sentinel" } */ extern void bar(void) { @@ -27,6 +35,23 @@ extern void bar(void) foo1 ("a", NULL, 1); /* { dg-warning "missing sentinel" "sentinel" } */ foo1 ("a", NULL); + foo5 ("a", 1, 2, 3, NULL); /* { dg-warning "missing sentinel" "sentinel" } */ + foo5 ("a", 1, 2, NULL, 3); + foo5 ("a", 1, NULL, 2, 3); /* { dg-warning "missing sentinel" "sentinel" } */ + foo5 ("a", NULL, 1, 2, 3); /* { dg-warning "missing sentinel" "sentinel" } */ + foo5 ("a", 0, 1, 2, 3); /* { dg-warning "missing sentinel" "sentinel" } */ + + foo6 ("a", 1, NULL); /* { dg-warning "not enough arguments" "sentinel" } */ + foo6 ("a", 1, NULL, 2); /* { dg-warning "not enough arguments" "sentinel" } */ + foo6 ("a", 1, NULL, 2, 3); /* { dg-warning "not enough arguments" "sentinel" } */ + foo6 ("a", NULL, 1, 2, 3); /* { dg-warning "not enough arguments" "sentinel" } */ + foo6 ("a", NULL, 1, 2, 3, 4); /* { dg-warning "missing sentinel" "sentinel" } */ + foo6 ("a", NULL, 1, 2, 3, 4, 5); + foo6 ("a", 0, 1, 2, 3, 4, 5); /* { dg-warning "missing sentinel" "sentinel" } */ + foo6 ("a", NULL, 1, 2, 3, 4, 5, 6); /* { dg-warning "missing sentinel" "sentinel" } */ + + foo7 ("a", 1, 2, 3, NULL); + execl ("/bin/ls", "-aFC"); /* { dg-warning "missing sentinel" "sentinel" } */ execl ("/bin/ls", "-aFC", 0); /* { dg-warning "missing sentinel" "sentinel" } */ execl ("/bin/ls", "-aFC", NULL); @@ -34,4 +59,8 @@ extern void bar(void) execlp ("ls", "-aFC"); /* { dg-warning "missing sentinel" "sentinel" } */ execlp ("ls", "-aFC", 0); /* { dg-warning "missing sentinel" "sentinel" } */ execlp ("ls", "-aFC", NULL); + + execle ("ls", "-aFC", ".", envp); /* { dg-warning "missing sentinel" "sentinel" } */ + execle ("ls", "-aFC", ".", 0, envp); /* { dg-warning "missing sentinel" "sentinel" } */ + execle ("ls", "-aFC", ".", NULL, envp); } -- 2.30.2