c-common.c (warn_nonnull): Declare.
* 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. From-SVN: r53790
This commit is contained in:
parent
9547983155
commit
b34c788149
@ -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.
|
||||
|
293
gcc/c-common.c
293
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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 },
|
||||
|
130
gcc/c-format.c
130
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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
39
gcc/testsuite/gcc.dg/nonnull-1.c
Normal file
39
gcc/testsuite/gcc.dg/nonnull-1.c
Normal file
@ -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" } */
|
||||
}
|
16
gcc/testsuite/gcc.dg/nonnull-2.c
Normal file
16
gcc/testsuite/gcc.dg/nonnull-2.c
Normal file
@ -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)
|
||||
{
|
||||
}
|
Loading…
Reference in New Issue
Block a user