On 12/07/2016 08:24 PM, Martin Sebor wrote:
You're right! Good chatch! I missed that there are two ways to
represent the same thing. For example, these two declarations
void __attribute ((nonnull (1, 2)))
f (void);
void __attribute ((nonnull (1))) __attribute ((nonnull (2)))
f (void);
apply to the same arguments but each is represented differently,
as is this one:
void __attribute ((nonnull))
f (void);
The builtins use the first form and I didn't have tests for user-
defined attributes in the second form. I've fixed that in the
attached updated patch (and added more tests). It does seem,
though, that it would be better to represent these declarations
canonically. It would simplify the processing and avoid bugs.
I'm not sure what the historical context is for having two forms of the
same thing. Though I would generally agree that there should be a
canonical form.
One more high level note. While I am in favor of adding these
attributes, they can cause interesting codegen issues that we need to be
on the lookout for.
Specifically when we see an SSA_NAME as an argument when the argument is
marked as NONNULL, the optimizers will try to use that information to
eliminate unnecessary NULL pointer checks.
The canonical example has been
memcpy (src, dst, 0)
[ stuff ]
if (src == 0)
whatever
GCC can sometimes follow things well enough to realize that the test, in
a conforming program, will always be false and remove the test. Some
have claimed this is undesirable behavior on GCC's part (and they may be
right).
Anyway, something to keep in mind. These changes may make GCC ever so
slightly more aggressive in its NULL pointer eliminations.
Thanks
Martin
gcc-78673.diff
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/78673
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/78673
PR c/17308
* c-common.c (check_nonnull_arg): Disable when optimization
is enabled.
gcc/testsuite/ChangeLog:
PR c/78673
PR c/17308
* gcc.dg/builtins-nonnull.c: New test.
* gcc.dg/nonnull-4.c: New test.
OK.
jeff