diff options
author | thorpej <thorpej@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-05-23 15:48:05 +0000 |
---|---|---|
committer | thorpej <thorpej@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-05-23 15:48:05 +0000 |
commit | dbf6c367801e1bf1d0cec09a2fe8fef7f7957c3f (patch) | |
tree | ec1ff9d3e5c1ac88998d2453691cca3c42bc0416 | |
parent | 43a852ea4edb3bace60c8f0880cdc1768ace6151 (diff) | |
download | gcc-dbf6c367801e1bf1d0cec09a2fe8fef7f7957c3f.tar.gz |
* c-common.c (warn_nonnull): Declare.
(c_common_attribute_table): Add "nonnull" attribute.
(handle_nonnull_attribute, check_function_nonnull, nonnull_check_p,
check_nonnull_arg, get_nonnull_operand, check_function_arguments,
check_function_arguments_recurse): New functions.
* c-common.h (warn_nonnull): Declare extern.
(check_function_arguments, check_function_arguments_recurse): New
prototypes.
* c-decl.c (c_decode_option): Add -Wnonnull option.
* c-format.c (set_Wformat): Set warn_nonnull if enabling
format checking.
(format_check_context): New structure.
(check_format_info_recurse): Remove recursion and rename to...
(check_format_arg): ...this. Update comment.
(check_format_info): Use check_function_arguments_recurse.
* c-typeck.c (build_function_call): Call check_function_arguments
instead of check_function_format.
* doc/extend.texi: Document "nonnull" attribute.
* doc/invoke.texi: Docuemnt -Wnonnull option.
* testsuite/gcc.dg/nonnull-1.c: New test.
* testsuite/gcc.dg/nonnull-2.c: New test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@53790 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 24 | ||||
-rw-r--r-- | gcc/c-common.c | 293 | ||||
-rw-r--r-- | gcc/c-common.h | 11 | ||||
-rw-r--r-- | gcc/c-decl.c | 1 | ||||
-rw-r--r-- | gcc/c-format.c | 130 | ||||
-rw-r--r-- | gcc/c-typeck.c | 5 | ||||
-rw-r--r-- | gcc/doc/extend.texi | 40 | ||||
-rw-r--r-- | gcc/doc/invoke.texi | 13 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/nonnull-1.c | 39 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/nonnull-2.c | 16 |
10 files changed, 468 insertions, 104 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d7334a9cb7a..be5370c4eae 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2002-05-23 Jason Thorpe <thorpej@wasabisystems.com> + + * c-common.c (warn_nonnull): Declare. + (c_common_attribute_table): Add "nonnull" attribute. + (handle_nonnull_attribute, check_function_nonnull, nonnull_check_p, + check_nonnull_arg, get_nonnull_operand, check_function_arguments, + check_function_arguments_recurse): New functions. + * c-common.h (warn_nonnull): Declare extern. + (check_function_arguments, check_function_arguments_recurse): New + prototypes. + * c-decl.c (c_decode_option): Add -Wnonnull option. + * c-format.c (set_Wformat): Set warn_nonnull if enabling + format checking. + (format_check_context): New structure. + (check_format_info_recurse): Remove recursion and rename to... + (check_format_arg): ...this. Update comment. + (check_format_info): Use check_function_arguments_recurse. + * c-typeck.c (build_function_call): Call check_function_arguments + instead of check_function_format. + * doc/extend.texi: Document "nonnull" attribute. + * doc/invoke.texi: Docuemnt -Wnonnull option. + * testsuite/gcc.dg/nonnull-1.c: New test. + * testsuite/gcc.dg/nonnull-2.c: New test. + 2002-05-23 David S. Miller <davem@redhat.com> * basic-block.h (CLEANUP_NO_INSN_DEL): Define it. diff --git a/gcc/c-common.c b/gcc/c-common.c index 900b5e9bb54..006a831cf3c 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -230,6 +230,11 @@ int warn_sequence_point; /* Nonzero means to warn about compile-time division by zero. */ int warn_div_by_zero = 1; +/* Warn about NULL being passed to argument slots marked as requiring + non-NULL. */ + +int warn_nonnull; + /* The elements of `ridpointers' are identifier nodes for the reserved type names and storage classes. It is indexed by a RID_... value. */ tree *ridpointers; @@ -344,8 +349,17 @@ static tree handle_deprecated_attribute PARAMS ((tree *, tree, tree, int, bool *)); static tree handle_vector_size_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_nonnull_attribute PARAMS ((tree *, tree, tree, int, + bool *)); static tree vector_size_helper PARAMS ((tree, tree)); +static void check_function_nonnull PARAMS ((tree, tree)); +static void check_nonnull_arg PARAMS ((void *, tree, + unsigned HOST_WIDE_INT)); +static bool nonnull_check_p PARAMS ((tree, unsigned HOST_WIDE_INT)); +static bool get_nonnull_operand PARAMS ((tree, + unsigned HOST_WIDE_INT *)); + /* Table of machine-independent attributes common to all C-like languages. */ const struct attribute_spec c_common_attribute_table[] = { @@ -406,6 +420,8 @@ const struct attribute_spec c_common_attribute_table[] = handle_vector_size_attribute }, { "visibility", 1, 1, true, false, false, handle_visibility_attribute }, + { "nonnull", 0, -1, false, true, true, + handle_nonnull_attribute }, { NULL, 0, 0, false, false, false, NULL } }; @@ -5599,3 +5615,280 @@ vector_size_helper (type, bottom) return outer; } + +/* Handle the "nonnull" attribute. */ +static tree +handle_nonnull_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name ATTRIBUTE_UNUSED; + tree args; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + tree type = *node; + unsigned HOST_WIDE_INT attr_arg_num; + + /* If no arguments are specified, all pointer arguments should be + non-null. Veryify a full prototype is given so that the arguments + will have the correct types when we actually check them later. */ + if (! args) + { + if (! TYPE_ARG_TYPES (type)) + { + error ("nonnull attribute without arguments on a non-prototype"); + *no_add_attrs = true; + } + return NULL_TREE; + } + + /* Argument list specified. Verify that each argument number references + a pointer argument. */ + for (attr_arg_num = 1; args; args = TREE_CHAIN (args)) + { + tree argument; + unsigned HOST_WIDE_INT arg_num, ck_num; + + if (! get_nonnull_operand (TREE_VALUE (args), &arg_num)) + { + error ("nonnull argument has invalid operand number (arg %lu)", + (unsigned long) attr_arg_num); + *no_add_attrs = true; + return NULL_TREE; + } + + argument = TYPE_ARG_TYPES (type); + if (argument) + { + for (ck_num = 1; ; ck_num++) + { + if (! argument || ck_num == arg_num) + break; + argument = TREE_CHAIN (argument); + } + + if (! argument + || TREE_CODE (TREE_VALUE (argument)) == VOID_TYPE) + { + error ("nonnull argument with out-of-range operand number (arg %lu, operand %lu)", + (unsigned long) attr_arg_num, (unsigned long) arg_num); + *no_add_attrs = true; + return NULL_TREE; + } + + if (TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE) + { + error ("nonnull argument references non-pointer operand (arg %lu, operand %lu)", + (unsigned long) attr_arg_num, (unsigned long) arg_num); + *no_add_attrs = true; + return NULL_TREE; + } + } + } + + return NULL_TREE; +} + +/* Check the argument list of a function call for null in argument slots + that are marked as requiring a non-null pointer argument. */ + +static void +check_function_nonnull (attrs, params) + tree attrs; + tree params; +{ + tree a, args, param; + int param_num; + + for (a = attrs; a; a = TREE_CHAIN (a)) + { + if (is_attribute_p ("nonnull", TREE_PURPOSE (a))) + { + args = TREE_VALUE (a); + + /* Walk the argument list. If we encounter an argument number we + should check for non-null, do it. If the attribute has no args, + then every pointer argument is checked (in which case the check + for pointer type is done in check_nonnull_arg). */ + for (param = params, param_num = 1; ; + param_num++, param = TREE_CHAIN (param)) + { + if (! param) + break; + if (! args || nonnull_check_p (args, param_num)) + check_function_arguments_recurse (check_nonnull_arg, NULL, + TREE_VALUE (param), + param_num); + } + } + } +} + +/* Helper for check_function_nonnull; given a list of operands which + must be non-null in ARGS, determine if operand PARAM_NUM should be + checked. */ + +static bool +nonnull_check_p (args, param_num) + tree args; + unsigned HOST_WIDE_INT param_num; +{ + unsigned HOST_WIDE_INT arg_num; + + for (; args; args = TREE_CHAIN (args)) + { + if (! get_nonnull_operand (TREE_VALUE (args), &arg_num)) + abort (); + + if (arg_num == param_num) + return true; + } + return false; +} + +/* Check that the function argument PARAM (which is operand number + PARAM_NUM) is non-null. This is called by check_function_nonnull + via check_function_arguments_recurse. */ + +static void +check_nonnull_arg (ctx, param, param_num) + void *ctx ATTRIBUTE_UNUSED; + tree param; + unsigned HOST_WIDE_INT param_num; +{ + /* Just skip checking the argument if it's not a pointer. This can + happen if the "nonnull" attribute was given without an operand + list (which means to check every pointer argument). */ + + if (TREE_CODE (TREE_TYPE (param)) != POINTER_TYPE) + return; + + if (integer_zerop (param)) + warning ("null argument where non-null required (arg %lu)", + (unsigned long) param_num); +} + +/* Helper for nonnull attribute handling; fetch the operand number + from the attribute argument list. */ + +static bool +get_nonnull_operand (arg_num_expr, valp) + tree arg_num_expr; + unsigned HOST_WIDE_INT *valp; +{ + /* Strip any conversions from the arg number and verify they + are constants. */ + while (TREE_CODE (arg_num_expr) == NOP_EXPR + || TREE_CODE (arg_num_expr) == CONVERT_EXPR + || TREE_CODE (arg_num_expr) == NON_LVALUE_EXPR) + arg_num_expr = TREE_OPERAND (arg_num_expr, 0); + + if (TREE_CODE (arg_num_expr) != INTEGER_CST + || TREE_INT_CST_HIGH (arg_num_expr) != 0) + return false; + + *valp = TREE_INT_CST_LOW (arg_num_expr); + return true; +} + +/* Check for valid arguments being passed to a function. */ +void +check_function_arguments (attrs, params) + tree attrs; + tree params; +{ + /* Check for null being passed in a pointer argument that must be + non-null. We also need to do this if format checking is enabled. */ + + if (warn_nonnull) + check_function_nonnull (attrs, params); + + /* Check for errors in format strings. */ + + if (warn_format) + check_function_format (NULL, attrs, params); +} + +/* Generic argument checking recursion routine. PARAM is the argument to + be checked. PARAM_NUM is the number of the argument. CALLBACK is invoked + once the argument is resolved. CTX is context for the callback. */ +void +check_function_arguments_recurse (callback, ctx, param, param_num) + void (*callback) PARAMS ((void *, tree, unsigned HOST_WIDE_INT)); + void *ctx; + tree param; + unsigned HOST_WIDE_INT param_num; +{ + if (TREE_CODE (param) == NOP_EXPR) + { + /* Strip coercion. */ + check_function_arguments_recurse (callback, ctx, + TREE_OPERAND (param, 0), param_num); + return; + } + + if (TREE_CODE (param) == CALL_EXPR) + { + tree type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (param, 0))); + tree attrs; + bool found_format_arg = false; + + /* See if this is a call to a known internationalization function + that modifies a format arg. Such a function may have multiple + format_arg attributes (for example, ngettext). */ + + for (attrs = TYPE_ATTRIBUTES (type); + attrs; + attrs = TREE_CHAIN (attrs)) + if (is_attribute_p ("format_arg", TREE_PURPOSE (attrs))) + { + tree inner_args; + tree format_num_expr; + int format_num; + int i; + + /* Extract the argument number, which was previously checked + to be valid. */ + format_num_expr = TREE_VALUE (TREE_VALUE (attrs)); + while (TREE_CODE (format_num_expr) == NOP_EXPR + || TREE_CODE (format_num_expr) == CONVERT_EXPR + || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR) + format_num_expr = TREE_OPERAND (format_num_expr, 0); + + if (TREE_CODE (format_num_expr) != INTEGER_CST + || TREE_INT_CST_HIGH (format_num_expr) != 0) + abort (); + + format_num = TREE_INT_CST_LOW (format_num_expr); + + for (inner_args = TREE_OPERAND (param, 1), i = 1; + inner_args != 0; + inner_args = TREE_CHAIN (inner_args), i++) + if (i == format_num) + { + check_function_arguments_recurse (callback, ctx, + TREE_VALUE (inner_args), + param_num); + found_format_arg = true; + break; + } + } + + /* If we found a format_arg attribute and did a recursive check, + we are done with checking this argument. Otherwise, we continue + and this will be considered a non-literal. */ + if (found_format_arg) + return; + } + + if (TREE_CODE (param) == COND_EXPR) + { + /* Check both halves of the conditional expression. */ + check_function_arguments_recurse (callback, ctx, + TREE_OPERAND (param, 1), param_num); + check_function_arguments_recurse (callback, ctx, + TREE_OPERAND (param, 2), param_num); + return; + } + + (*callback) (ctx, param, param_num); +} diff --git a/gcc/c-common.h b/gcc/c-common.h index 320d03d8253..834d78520dc 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -426,6 +426,11 @@ extern int warn_format_nonliteral; extern int warn_format_security; +/* Warn about NULL being passed to argument slots marked as requiring + non-NULL. */ + +extern int warn_nonnull; + /* Warn about possible violations of sequence point rules. */ extern int warn_sequence_point; @@ -522,6 +527,12 @@ extern const char *fname_as_string PARAMS ((int)); extern tree fname_decl PARAMS ((unsigned, tree)); extern const char *fname_string PARAMS ((unsigned)); +extern void check_function_arguments PARAMS ((tree, tree)); +extern void check_function_arguments_recurse PARAMS ((void (*) (void *, + tree, + unsigned HOST_WIDE_INT), + void *, tree, + unsigned HOST_WIDE_INT)); extern void check_function_format PARAMS ((int *, tree, tree)); extern void set_Wformat PARAMS ((int)); extern tree handle_format_attribute PARAMS ((tree *, tree, tree, diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 0890a2a58c4..3dcb05540ec 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -489,6 +489,7 @@ c_decode_option (argc, argv) { "missing-prototypes", &warn_missing_prototypes }, { "multichar", &warn_multichar }, { "nested-externs", &warn_nested_externs }, + { "nonnull", &warn_nonnull }, { "parentheses", &warn_parentheses }, { "pointer-arith", &warn_pointer_arith }, { "redundant-decls", &warn_redundant_decls }, diff --git a/gcc/c-format.c b/gcc/c-format.c index dc73f4d69f1..b3640c50190 100644 --- a/gcc/c-format.c +++ b/gcc/c-format.c @@ -71,6 +71,9 @@ set_Wformat (setting) warn_format_nonliteral = setting; warn_format_security = setting; } + /* Make sure not to disable -Wnonnull if -Wformat=0 is specified. */ + if (setting) + warn_nonnull = setting; } @@ -900,10 +903,16 @@ typedef struct int number_other; } format_check_results; +typedef struct +{ + format_check_results *res; + function_format_info *info; + tree params; + int *status; +} format_check_context; + static void check_format_info PARAMS ((int *, function_format_info *, tree)); -static void check_format_info_recurse PARAMS ((int *, format_check_results *, - function_format_info *, tree, - tree, unsigned HOST_WIDE_INT)); +static void check_format_arg PARAMS ((void *, tree, unsigned HOST_WIDE_INT)); static void check_format_info_main PARAMS ((int *, format_check_results *, function_format_info *, const char *, int, tree, @@ -1294,6 +1303,7 @@ check_format_info (status, info, params) function_format_info *info; tree params; { + format_check_context format_ctx; unsigned HOST_WIDE_INT arg_num; tree format_tree; format_check_results res; @@ -1320,7 +1330,13 @@ check_format_info (status, info, params) res.number_unterminated = 0; res.number_other = 0; - check_format_info_recurse (status, &res, info, format_tree, params, arg_num); + format_ctx.res = &res; + format_ctx.info = info; + format_ctx.params = params; + format_ctx.status = status; + + check_function_arguments_recurse (check_format_arg, &format_ctx, + format_tree, arg_num); if (res.number_non_literal > 0) { @@ -1377,110 +1393,34 @@ check_format_info (status, info, params) status_warning (status, "unterminated format string"); } - -/* Recursively check a call to a format function. FORMAT_TREE is the - format parameter, which may be a conditional expression in which - both halves should be checked. ARG_NUM is the number of the - format argument; PARAMS points just after it in the argument list. */ +/* Callback from check_function_arguments_recurse to check a + format string. FORMAT_TREE is the format parameter. ARG_NUM + is the number of the format argument. CTX points to a + format_check_context. */ static void -check_format_info_recurse (status, res, info, format_tree, params, arg_num) - int *status; - format_check_results *res; - function_format_info *info; +check_format_arg (ctx, format_tree, arg_num) + void *ctx; tree format_tree; - tree params; unsigned HOST_WIDE_INT arg_num; { + format_check_context *format_ctx = ctx; + format_check_results *res = format_ctx->res; + function_format_info *info = format_ctx->info; + tree params = format_ctx->params; + int *status = format_ctx->status; + int format_length; HOST_WIDE_INT offset; const char *format_chars; tree array_size = 0; tree array_init; - if (TREE_CODE (format_tree) == NOP_EXPR) - { - /* Strip coercion. */ - check_format_info_recurse (status, res, info, - TREE_OPERAND (format_tree, 0), params, - arg_num); - return; - } - - if (TREE_CODE (format_tree) == CALL_EXPR) - { - tree type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (format_tree, 0))); - tree attrs; - bool found_format_arg = false; - - /* See if this is a call to a known internationalization function - that modifies the format arg. Such a function may have multiple - format_arg attributes (for example, ngettext). */ - - for (attrs = TYPE_ATTRIBUTES (type); - attrs; - attrs = TREE_CHAIN (attrs)) - if (is_attribute_p ("format_arg", TREE_PURPOSE (attrs))) - { - tree inner_args; - tree format_num_expr; - int format_num; - int i; - - /* Extract the argument number, which was previously checked - to be valid. */ - format_num_expr = TREE_VALUE (TREE_VALUE (attrs)); - while (TREE_CODE (format_num_expr) == NOP_EXPR - || TREE_CODE (format_num_expr) == CONVERT_EXPR - || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR) - format_num_expr = TREE_OPERAND (format_num_expr, 0); - - if (TREE_CODE (format_num_expr) != INTEGER_CST - || TREE_INT_CST_HIGH (format_num_expr) != 0) - abort (); - - format_num = TREE_INT_CST_LOW (format_num_expr); - - for (inner_args = TREE_OPERAND (format_tree, 1), i = 1; - inner_args != 0; - inner_args = TREE_CHAIN (inner_args), i++) - if (i == format_num) - { - check_format_info_recurse (status, res, info, - TREE_VALUE (inner_args), params, - arg_num); - found_format_arg = true; - break; - } - } - - /* If we found a format_arg attribute and did a recursive check, - we are done with checking this format string. Otherwise, we - continue and this will count as a non-literal format string. */ - if (found_format_arg) - return; - } - - if (TREE_CODE (format_tree) == COND_EXPR) - { - /* Check both halves of the conditional expression. */ - check_format_info_recurse (status, res, info, - TREE_OPERAND (format_tree, 1), params, - arg_num); - check_format_info_recurse (status, res, info, - TREE_OPERAND (format_tree, 2), params, - arg_num); - return; - } - if (integer_zerop (format_tree)) { - /* FIXME: this warning should go away once Marc Espie's - __attribute__((nonnull)) patch is in. Instead, checking for - nonnull attributes should probably change this function to act - specially if info == NULL and add a res->number_null entry for - that case, or maybe add a function pointer to be called at - the end instead of hardcoding check_format_info_main. */ + /* FIXME: instead of warning about a null format string here, + functions for which we want to perform this check should be + marked with the "nonnull" attribute on the appropriate arguments. */ status_warning (status, "null format string"); /* Skip to first argument to check, so we can see if this format diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 7e91d4fc692..76ebc3416d9 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -1576,10 +1576,9 @@ build_function_call (function, params) coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype), params, name, fundecl); - /* Check for errors in format strings. */ + /* Check that the arguments to the function are valid. */ - if (warn_format) - check_function_format (NULL, TYPE_ATTRIBUTES (fntype), coerced_params); + check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params); /* Recognize certain built-in functions so we can make tree-codes other than CALL_EXPR. We do this when it enables fold-const.c diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 4209f2a5dbc..301db237124 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -1869,6 +1869,7 @@ the enclosing block. @cindex @code{volatile} applied to function @cindex @code{const} applied to function @cindex functions with @code{printf}, @code{scanf}, @code{strftime} or @code{strfmon} style arguments +@cindex functions with non-null pointer arguments @cindex functions that are passed arguments in registers on the 386 @cindex functions that pop the argument stack on the 386 @cindex functions that do not pop the argument stack on the 386 @@ -1885,11 +1886,11 @@ attributes are currently defined for functions on all targets: @code{pure}, @code{const}, @code{format}, @code{format_arg}, @code{no_instrument_function}, @code{section}, @code{constructor}, @code{destructor}, @code{used}, -@code{unused}, @code{deprecated}, @code{weak}, @code{malloc}, and -@code{alias}. Several other attributes are defined for functions on -particular target systems. Other attributes, including @code{section} -are supported for variables declarations (@pxref{Variable Attributes}) -and for types (@pxref{Type Attributes}). +@code{unused}, @code{deprecated}, @code{weak}, @code{malloc}, +@code{alias}, and @code{nonnull}. Several other attributes are defined +for functions on particular target systems. Other attributes, including +@code{section} are supported for variables declarations +(@pxref{Variable Attributes}) and for types (@pxref{Type Attributes}). You may also specify attributes with @samp{__} preceding and following each keyword. This allows you to use them in header files without @@ -2101,6 +2102,35 @@ requested by @option{-ansi} or an appropriate @option{-std} option, or @option{-ffreestanding} is used. @xref{C Dialect Options,,Options Controlling C Dialect}. +@item nonnull (@var{arg-index,...}) +@cindex @code{nonnull} function attribute +The @code{nonnull} attribute specifies that some function parameters should +be non-null pointers. For instance, the declaration: + +@smallexample +extern void * +my_memcpy (void *dest, const void *src, size_t len) + __attribute__((nonnull (1, 2))); +@end smallexample + +@noindent +causes the compiler to check that, in calls to @code{my_memcpy}, +arguments @var{dest} and @var{src} are non-null. If the compiler +determines that a null pointer is passed in an argument slot marked +as non-null, and the @option{-Wnonnull} option is enabled, a warning +is issued. The compiler may also choose to make optimizations based +on the knowledge that certain function arguments will not be null. + +If no argument index list is given to the @code{nonnull} attribute, +all pointer arguments are marked as non-null. To illustrate, the +following declaration is equivalent to the previous example: + +@smallexample +extern void * +my_memcpy (void *dest, const void *src, size_t len) + __attribute__((nonnull)); +@end smallexample + @item no_instrument_function @cindex @code{no_instrument_function} function attribute @opindex finstrument-functions diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index cedabdf5500..1ab9cb39f98 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -225,7 +225,7 @@ in the following sections. -Wmain -Wmissing-braces -Wmissing-declarations @gol -Wmissing-format-attribute -Wmissing-noreturn @gol -Wno-multichar -Wno-format-extra-args -Wno-format-y2k @gol --Wno-import -Wpacked -Wpadded @gol +-Wno-import -Wnonnull -Wpacked -Wpadded @gol -Wparentheses -Wpointer-arith -Wredundant-decls @gol -Wreturn-type -Wsequence-point -Wshadow @gol -Wsign-compare -Wswitch -Wswitch-default -Wswitch-enum @gol @@ -1842,6 +1842,9 @@ in the selected standard version (but not for @code{strfmon} formats, since those are not in any version of the C standard). @xref{C Dialect Options,,Options Controlling C Dialect}. +Since @option{-Wformat} also checks for null format arguments for +several functions, @option{-Wformat} also implies @option{-Wnonnull}. + @option{-Wformat} is included in @option{-Wall}. For more control over some aspects of format checking, the options @option{-Wno-format-y2k}, @option{-Wno-format-extra-args}, @option{-Wno-format-zero-length}, @@ -1896,6 +1899,14 @@ Enable @option{-Wformat} plus format checks not included in @option{-Wformat}. Currently equivalent to @samp{-Wformat -Wformat-nonliteral -Wformat-security}. +@item -Wnonnull +@opindex Wnonnull +Enable warning about passing a null pointer for arguments marked as +requiring a non-null value by the @code{nonnull} function attribute. + +@option{-Wnonnull} is included in @option{-Wall} and @option{-Wformat}. It +can be disabled with the @option{-Wno-nonnull} option. + @item -Wimplicit-int @opindex Wimplicit-int Warn when a declaration does not specify a type. diff --git a/gcc/testsuite/gcc.dg/nonnull-1.c b/gcc/testsuite/gcc.dg/nonnull-1.c new file mode 100644 index 00000000000..51a8a3373ee --- /dev/null +++ b/gcc/testsuite/gcc.dg/nonnull-1.c @@ -0,0 +1,39 @@ +/* Test for the "nonnull" function attribute. */ +/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */ +/* { dg-do compile } */ +/* { dg-options "-Wnonnull" } */ + +#include <stddef.h> + +extern void func1 (char *, char *, int) __attribute__((nonnull)); + +extern void func2 (char *, char *) __attribute__((nonnull(1))); + +extern void func3 (char *, int, char *, int) + __attribute__((nonnull(1,3))); + +extern void func4 (char *, char *) __attribute__((nonnull(1))) + __attribute__((nonnull(2))); + +void +foo (int i1, int i2, int i3, char *cp1, char *cp2, char *cp3) +{ + func1(cp1, cp2, i1); + + func1(NULL, cp2, i1); /* { dg-warning "null" "null with argless nonnull 1" } */ + func1(cp1, NULL, i1); /* { dg-warning "null" "null with argless nonnull 2" } */ + func1(cp1, cp2, 0); + + func2(cp1, NULL); + func2(NULL, cp1); /* { dg-warning "null" "null with single explicit nonnull" } */ + + func3(NULL, i2, cp3, i3); /* { dg-warning "null" "null with explicit nonnull 1" } */ + func3(cp3, i2, NULL, i3); /* { dg-warning "null" "null with explicit nonnull 3" } */ + + func1(i1 ? cp1 : NULL, cp2, i3); /* { dg-warning "null" "null with cond expr rhs" } */ + func1(i1 ? NULL : cp1, cp2, i3); /* { dg-warning "null" "null with cond expr lhs" } */ + func1(i1 ? (i2 ? cp1 : NULL) : cp2, cp3, i3); /* { dg-warning "null" "null with nested cond expr" } */ + + func4(NULL, cp1); /* { dg-warning "null" "null with multiple attributes 1" } */ + func4(cp1, NULL); /* { dg-warning "null" "null with multiple attributes 2" } */ +} diff --git a/gcc/testsuite/gcc.dg/nonnull-2.c b/gcc/testsuite/gcc.dg/nonnull-2.c new file mode 100644 index 00000000000..bd36d232d38 --- /dev/null +++ b/gcc/testsuite/gcc.dg/nonnull-2.c @@ -0,0 +1,16 @@ +/* Test for the invalid use of the "nonnull" function attribute. */ +/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */ +/* { dg-do compile } */ + +extern void func1 () __attribute__((nonnull)); /* { dg-error "without arguments" } */ + +extern void func2 (char *) __attribute__((nonnull(2))); /* { dg-error "out-of-range operand" } */ + +extern void func3 (char *) __attribute__((nonnull(foo))); /* { dg-error "invalid operand number" } */ + +extern void func4 (int) __attribute__((nonnull(1))); /* { dg-error "references non-pointer" } */ + +void +foo (void) +{ +} |