On 05/10/2018 01:26 PM, Martin Sebor wrote:
> GCC 8.1 warns for unbounded (and some bounded) string comparisons
> involving arrays declared attribute nonstring (i.e., char arrays
> that need not be nul-terminated).  For instance:
> 
>   extern __attribute__((nonstring)) char a[4];
> 
>   int f (void)
>   {
>     return strncmp (a, "123", sizeof a);
>   }
> 
>   warning: ‘strcmp’ argument 1 declared attribute ‘nonstring’
> 
> Note that the warning refers to strcmp even though the call in
> the source is to strncmp, because prior passes transform one to
> the other.
> 
> The warning above is unnecessary (for strcmp) and incorrect for
> strncmp because the call reads exactly four bytes from the non-
> string array a regardless of the bound and so there is no risk
> that it will read past the end of the array.
> 
> The attached change enhances the warning to use the length of
> the string argument to suppress some of these needless warnings
> for both bounded and unbounded string comparison functions.
> When the length of the string is unknown, the warning uses its
> size (when possible) as the upper bound on the number of accessed
> bytes.  The change adds no new warnings.
> 
> I'm looking for approval to commit it to both trunk and 8-branch.
> 
> Martin
> 
> gcc-85623.diff
> 
> 
> PR c/85623 - strncmp() warns about attribute 'nonstring' incorrectly in 
> -Wstringop-overflow
> 
> gcc/ChangeLog:
> 
>       PR c/85623
>       * calls.c (maybe_warn_nonstring_arg): Use string length to set
>       or ajust the presumed bound on an operation to avoid unnecessary
>       warnings.
s/ajust/adjust/

> 
> gcc/testsuite/ChangeLog:
> 
>       PR c/85623
>       * c-c++-common/attr-nonstring-3.c: Adjust.
>       * c-c++-common/attr-nonstring-4.c: Adjust.
>       * c-c++-common/attr-nonstring-6.c: New test.
> 
> diff --git a/gcc/calls.c b/gcc/calls.c
> index 9eb0467..f5c8ad4 100644
> --- a/gcc/calls.c
> +++ b/gcc/calls.c
> @@ -55,6 +55,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "stringpool.h"
>  #include "attribs.h"
>  #include "builtins.h"
> +#include "gimple-fold.h"
>  
>  /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits.  */
>  #define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)
> @@ -1612,15 +1613,36 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
>    /* The bound argument to a bounded string function like strncpy.  */
>    tree bound = NULL_TREE;
>  
> +  /* The range of lengths of a string argument to one of the comparison
> +     functions.  If the length is less than the bound it is used instead.  */
> +  tree lenrng[2] = { NULL_TREE, NULL_TREE };
> +
>    /* It's safe to call "bounded" string functions with a non-string
>       argument since the functions provide an explicit bound for this
>       purpose.  */
>    switch (DECL_FUNCTION_CODE (fndecl))
>      {
> -    case BUILT_IN_STPNCPY:
> -    case BUILT_IN_STPNCPY_CHK:
> +    case BUILT_IN_STRCMP:
>      case BUILT_IN_STRNCMP:
>      case BUILT_IN_STRNCASECMP:
> +      {
> +     /* For these, if one argument refers to one or more of a set
> +        of string constants or arrays of known size, determine
> +        the range of their known or possible lengths and use it
> +        conservatively as the bound for the unbounded function,
> +        and to adjust the range of the bound of the bounded ones.  */
> +     unsigned stride = with_bounds ? 2 : 1;
> +     for (unsigned argno = 0; argno < nargs && !*lenrng; argno += stride)
> +       {
> +         tree arg = CALL_EXPR_ARG (exp, argno);
> +         if (!get_attr_nonstring_decl (arg))
> +           get_range_strlen (arg, lenrng);
> +       }
> +      }
> +      /* Fall through.  */
> +
> +    case BUILT_IN_STPNCPY:
> +    case BUILT_IN_STPNCPY_CHK:
>      case BUILT_IN_STRNCPY:
>      case BUILT_IN_STRNCPY_CHK:
>        {
> @@ -1647,6 +1669,33 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
> +     {
> +       /* Replace the bound on the oparation with the upper bound
s/oparation/operation/

OK for the trunk with the nits fixed.

Also note that I've acked a patch from Martin L (I believe) that removes
the chkp/bounds checking bits that were deprecated in gcc-8.  So there's
some chance the bounds-related bits will need to be updated depending on
whether or not Martin's L's patch has been committed.

This isn't strictly a regression.  So unless this is affecting some
critical code (ie glibc, kernel or something similar) this probably
would require an explicit OK from Jakub or Richi to be eligible for the
gcc-8 branch.

jeff

Reply via email to