summaryrefslogtreecommitdiff
path: root/gcc/c-format.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c-format.c')
-rw-r--r--gcc/c-format.c130
1 files changed, 35 insertions, 95 deletions
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