aboutsummaryrefslogtreecommitdiff
path: root/gcc/calls.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2016-12-14 17:23:16 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2016-12-14 10:23:16 -0700
commit474da67ef9ec3658e4da9deb5373353532b2a840 (patch)
tree9216700dc546aef48d9bff1a0ab2203160ce0f8e /gcc/calls.c
parentb4ba0852099ad28a533327ac25e8337910be28e8 (diff)
downloadgcc-474da67ef9ec3658e4da9deb5373353532b2a840.zip
gcc-474da67ef9ec3658e4da9deb5373353532b2a840.tar.gz
gcc-474da67ef9ec3658e4da9deb5373353532b2a840.tar.bz2
PR c/78673 - sprintf missing attribute nonnull on destination argument
PR c/78673 - sprintf missing attribute nonnull on destination argument PR c/17308 - nonnull attribute not as useful as it could be gcc/ChangeLog: PR c/17308 * builtin-attrs.def (ATTR_NONNULL_1_1, ATTR_NONNULL_1_2): Defined. (ATTR_NONNULL_1_3, ATTR_NONNULL_1_4, ATTR_NONNULL_1_5): Same. (ATTR_NOTHROW_NONNULL_1_1, ATTR_NOTHROW_NONNULL_1_2): Same. (ATTR_NOTHROW_NONNULL_1_3, ATTR_NOTHROW_NONNULL_1_4): Same. (ATTR_NOTHROW_NONNULL_1_5): Same. (ATTR_NONNULL_1_FORMAT_PRINTF_1_2): Same. (ATTR_NONNULL_1_FORMAT_PRINTF_2_0): Same. (ATTR_NONNULL_1_FORMAT_PRINTF_2_3): Same. (ATTR_NONNULL_1_FORMAT_PRINTF_3_0): Same. (ATTR_NONNULL_1_FORMAT_PRINTF_3_4): Same. (ATTR_NONNULL_1_FORMAT_PRINTF_4_0): Same. (ATTR_NONNULL_1_FORMAT_PRINTF_4_5): Same. * builtins.c (validate_arg): Add argument. Treat null pointers passed to nonnull arguments as invalid. (validate_arglist): Same. * builtins.def (fprintf, fprintf_unlocked): Add nonnull attribute. (printf, printf_unlocked, sprintf. vfprintf, vsprintf): Same. (__sprintf_chk, __vsprintf_chk, __fprintf_chk, __vfprintf_chk): Same. * calls.c (get_nonnull_ags, maybe_warn_null_arg): New functions. (initialize_argument_information): Diagnose null pointers passed to arguments declared nonnull. * calls.h (get_nonnull_args): Declared. gcc/c-family/ChangeLog: PR c/17308 * c-common.c (check_nonnull_arg): Disable when optimization is enabled. gcc/testsuite/ChangeLog: PR c/17308 * gcc.dg/builtins-nonnull.c: New test. * gcc.dg/nonnull-4.c: New test. From-SVN: r243661
Diffstat (limited to 'gcc/calls.c')
-rw-r--r--gcc/calls.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/gcc/calls.c b/gcc/calls.c
index bc3cbd5..8466427 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -1501,6 +1501,91 @@ maybe_complain_about_tail_call (tree call_expr, const char *reason)
error_at (EXPR_LOCATION (call_expr), "cannot tail-call: %s", reason);
}
+/* Return a bitmap with a bit set corresponding to each argument in
+ a function call expression CALLEXPR declared with attribute nonnull,
+ or null if none of the function's argument are nonnull. The caller
+ must free the bitmap. */
+
+bitmap
+get_nonnull_args (const_tree callexpr)
+{
+ tree fn = CALL_EXPR_FN (callexpr);
+ if (!fn || TREE_CODE (fn) != ADDR_EXPR)
+ return NULL;
+
+ tree fndecl = TREE_OPERAND (fn, 0);
+ tree fntype = TREE_TYPE (fndecl);
+ tree attrs = TYPE_ATTRIBUTES (fntype);
+ if (!attrs)
+ return NULL;
+
+ bitmap argmap = NULL;
+
+ /* A function declaration can specify multiple attribute nonnull,
+ each with zero or more arguments. The loop below creates a bitmap
+ representing a union of all the arguments. An empty (but non-null)
+ bitmap means that all arguments have been declaraed nonnull. */
+ for ( ; attrs; attrs = TREE_CHAIN (attrs))
+ {
+ attrs = lookup_attribute ("nonnull", attrs);
+ if (!attrs)
+ break;
+
+ if (!argmap)
+ argmap = BITMAP_ALLOC (NULL);
+
+ if (!TREE_VALUE (attrs))
+ {
+ /* Clear the bitmap in case a previous attribute nonnull
+ set it and this one overrides it for all arguments. */
+ bitmap_clear (argmap);
+ return argmap;
+ }
+
+ /* Iterate over the indices of the format arguments declared nonnull
+ and set a bit for each. */
+ for (tree idx = TREE_VALUE (attrs); idx; idx = TREE_CHAIN (idx))
+ {
+ unsigned int val = TREE_INT_CST_LOW (TREE_VALUE (idx)) - 1;
+ bitmap_set_bit (argmap, val);
+ }
+ }
+
+ return argmap;
+}
+
+/* In a call EXP to a function FNDECL some of whose arguments may have
+ been declared with attribute nonnull as described by NONNULLARGS,
+ check actual argument ARG at the zero-based position ARGPOS for
+ equality to null and issue a warning if it is not expected to be. */
+
+static void
+maybe_warn_null_arg (tree fndecl, tree exp, tree arg,
+ unsigned argpos, bitmap nonnullargs)
+{
+ if (!optimize
+ || !nonnullargs
+ || TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE
+ || !integer_zerop (arg)
+ || (!bitmap_empty_p (nonnullargs)
+ && !bitmap_bit_p (nonnullargs, argpos)))
+ return;
+
+ ++argpos;
+
+ location_t exploc EXPR_LOCATION (exp);
+
+ if (warning_at (exploc, OPT_Wnonnull,
+ "argument %u null where non-null expected", argpos))
+ {
+ if (DECL_IS_BUILTIN (fndecl))
+ inform (exploc, "in a call to built-in function %qD", fndecl);
+ else
+ inform (DECL_SOURCE_LOCATION (fndecl),
+ "in a call to function %qD declared here", fndecl);
+ }
+}
+
/* Fill in ARGS_SIZE and ARGS array based on the parameters found in
CALL_EXPR EXP.
@@ -1684,6 +1769,9 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
/* Array for up to the two attribute alloc_size arguments. */
tree alloc_args[] = { NULL_TREE, NULL_TREE };
+ /* Get a bitmap of pointer argument numbers declared attribute nonnull. */
+ bitmap nonnullargs = get_nonnull_args (exp);
+
/* I counts args in order (to be) pushed; ARGPOS counts in order written. */
for (argpos = 0; argpos < num_actuals; i--, argpos++)
{
@@ -1915,6 +2003,11 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
if (args[i].locate.size.var)
ADD_PARM_SIZE (*args_size, args[i].locate.size.var);
+ /* Check pointer argument for equality to NULL that is being passed
+ to arguments declared with attribute nonnull and warn. */
+ maybe_warn_null_arg (fndecl, exp, args[i].tree_value, argpos,
+ nonnullargs);
+
/* Increment ARGS_SO_FAR, which has info about which arg-registers
have been used, etc. */
@@ -1935,6 +2028,8 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
alloc_size. */
maybe_warn_alloc_args_overflow (fndecl, exp, alloc_args, alloc_idx);
}
+
+ BITMAP_FREE (nonnullargs);
}
/* Update ARGS_SIZE to contain the total size for the argument block.