On 11/13/2017 06:21 PM, Martin Sebor wrote:
> Attached is an improved version that rather than hardcoding
> the built-in functions to check uses the constness of each
> built-in's char* argument as a trigger to do the checking.
> 
> This avoids the problem of the list being incomplete either
> by omission or due to getting out of sync, and also makes it
> trivial to extend the same approach to user-defined functions
> in the future.
> 
> I've excluded strndup and strnlen (but no other "bounded"
> string functions like strncmp) from the checking.
> 
> Martin
> 
> On 11/12/2017 05:52 PM, Martin Sebor wrote:
>> The recently introduced -Wstringop-truncation warning relies
>> on the new nonstring attribute to allow the historical use case
>> of calling strncpy to completely fill the destination with a copy
>> of a string without adding a terminating nul.  Glibc is currently
>> considering making use of the attribute to decorate some of its
>> data members.  To help find misuses of such data members in
>> arguments to string functions like strlen or strdup, the attached
>> patch adds checking for this new attribute in these contexts.
>> The checking is intentionally done late so  that uses such arrays
>> that can be proven to be safe (and thus folded) are not diagnosed.
>>
>> While testing this simple enhancement I noticed that the handling
>> I added for the nul termination in cases like
>>
>>   strncpy (array, s, sizeof array);
>>   array[sizeof array - 1] = 0;
>>
>> to avoid the new warning wasn't quite as robust as it could and
>> arguably should be so I improved it a bit to silently accept
>> more forms of the idiom.  For instance, this is now correctly
>> handled (and not diagnosed):
>>
>>   *stpcpy (array, s, sizeof array - 1) = 0;
>>
>> Martin
>>
>> PS A useful future enhancement would be to detect the one byte
>> overflow in:
>>
>>   *stpcpy (array, s, sizeof array) = 0;
> 
> 
> gcc-82945.diff
> 
> 
> PR tree-optimization/82945 - add warning for passing non-strings to functions 
> that expect string arguments
> 
> gcc/ChangeLog:
> 
>       PR tree-optimization/82945
>       * calls.c (get_attr_nonstring_decl, maybe_warn_nonstring_arg): New
>       functions.
>       (initialize_argument_information): Call maybe_warn_nonstring_arg.
>       * calls.h (get_attr_nonstring_decl): Declare new function.
>       * doc/extend.texi (attribute nonstring): Update.
>       * gimple-fold.c (gimple_fold_builtin_strncpy): Call
>       get_attr_nonstring_decl and handle it.
>       * tree-ssa-strlen.c (maybe_diag_stxncpy_trunc): Same.  Improve
>       detection of nul-termination.
> 
> gcc/testsuite/ChangeLog:
> 
>       PR tree-optimization/82945
>       * c-c++-common/Wstringop-truncation-2.c: New test.
>       * c-c++-common/Wstringop-truncation.c: Adjust.
>       * c-c++-common/attr-nonstring-2.c: Adjust.
>       * c-c++-common/attr-nonstring-3.c: New test.

> 
> diff --git a/gcc/calls.c b/gcc/calls.c
> index 3730f43..197d907 100644
> --- a/gcc/calls.c
> +++ b/gcc/calls.c
> @@ -1494,6 +1494,108 @@ maybe_warn_alloc_args_overflow (tree fn, tree exp, 
> tree args[2], int idx[2])
>      }
>  }
>  
> +/* If EXPR refers to a character array or pointer declared attribute
> +   nonstring return a decl for that array or pointer and set *REF to
> +   the referenced enclosing object or pointer.  Otherwise returns
> +   null.  */
Generally we'd write NULL rather than null for a generic pointer and in
this specific case NULL_TREE is even better.

> +
> +tree
> +get_attr_nonstring_decl (tree expr, tree *ref)
> +{
> +  tree dcl = expr;
I think Jakub may have pointed this out, but we generally prefer decl.
Truly a nit though.


> +  if (TREE_CODE (dcl) == SSA_NAME)
> +    {
> +      if (SSA_NAME_IS_DEFAULT_DEF (dcl))
> +     dcl = SSA_NAME_VAR (dcl);
> +      else
> +     {
> +       gimple *def = SSA_NAME_DEF_STMT (dcl);
> +
> +       if (is_gimple_assign (def))
> +         {
> +           tree_code code = gimple_assign_rhs_code (def);
> +           if (code == ADDR_EXPR
> +               || code == COMPONENT_REF
> +               || code == VAR_DECL)
> +             dcl = gimple_assign_rhs1 (def);
Note that COMPONENT_REFs can have arguments that are themselves
COMPONENT_REFS.  So you typically want to use a loop to strip all away.




> +  /* It's safe to call strndup and strnlen with a non-string argument
> +     since the functions provide an explicit bound for this purpose.  */
> +  if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRNDUP)
> +    return;
So I see you handle BUILT_IN_STRNDUP here, but not BUILT_IN_STRNLEN.  Is
there a reason for the omission?


Jeff

Reply via email to