On 10/29/18 5:51 PM, Martin Sebor wrote:
> The missing nul detection fails when the argument of the %s or
> similar sprintf directive is the address of a non-nul character
> constant such as in:
> 
>   const char c = 'a';
>   int f (void)
>   {
>     return snprintf (0, 0, "%s", &c);
>   }
> 
> This is because the string_constant function only succeeds for
> arguments that refer to STRRING_CSTs, not to individual characters.
> 
> For the same reason, calls to memchr() such as the one below aren't
> folded into constants:
> 
>   const char d = '\0';
>   void* g (void)
>   {
>     return memchr (&d, 0, 1);
>   }
> 
> To detect and diagnose the missing nul in the first example and
> to fold the second, the attached patch modifies string_constant
> to return a synthesized STRING_CST object for such references
> (while also indicating whether such an object is properly
> nul-terminated).
> 
> Tested on x86_64-linux.
> 
> Martin
> 
> gcc-87756.diff
> 
> PR tree-optimization/87756 - missing unterminated argument warning using 
> address of a constant character
> 
> gcc/ChangeLog:
> 
>       PR tree-optimization/87756
>       * expr.c (string_constant): Synthesize a string literal from
>       the address of a constant character.
>       * tree.c (build_string_literal): Add an argument.
>       * tree.h (build_string_literal): Same.
> 
> gcc/testsuite/ChangeLog:
> 
>       PR tree-optimization/87756
>       * gcc.dg/builtin-memchr-2.c: New test.
>       * gcc.dg/builtin-memchr-3.c: Same.
>       * gcc.dg/warn-sprintf-no-nul-2.c: Same.
> 
> Index: gcc/expr.c
> ===================================================================
> --- gcc/expr.c        (revision 265496)
> +++ gcc/expr.c        (working copy)
> @@ -11484,18 +11484,40 @@ string_constant (tree arg, tree *ptr_offset, tree
>       offset = off;
>      }
>  
> -  if (!init || TREE_CODE (init) != STRING_CST)
> +  if (!init)
>      return NULL_TREE;
>  
> +  *ptr_offset = offset;
> +
> +  tree eltype = TREE_TYPE (init);
> +  tree initsize = TYPE_SIZE_UNIT (eltype);
>    if (mem_size)
> -    *mem_size = TYPE_SIZE_UNIT (TREE_TYPE (init));
> +    *mem_size = initsize;
> +
>    if (decl)
>      *decl = array;
>  
> -  gcc_checking_assert (tree_to_shwi (TYPE_SIZE_UNIT (TREE_TYPE (init)))
> -                    >= TREE_STRING_LENGTH (init));
> +  if (TREE_CODE (init) == INTEGER_CST)
> +    {
> +      /* For a reference to (address of) a single constant character,
> +      store the native representation of the character in CHARBUF.   */
> +      unsigned char charbuf[MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT];
> +      int len = native_encode_expr (init, charbuf, sizeof charbuf, 0);
> +      if (len > 0)
> +     {
> +       /* Construct a string literal with elements of ELTYPE and
> +          the representation above.  Then strip
> +          the ADDR_EXPR (ARRAY_REF (...)) around the STRING_CST.  */
> +       init = build_string_literal (len, (char *)charbuf, eltype);
> +       init = TREE_OPERAND (TREE_OPERAND (init, 0), 0);
> +     }
> +    }
>  
> -  *ptr_offset = offset;
> +  if (TREE_CODE (init) != STRING_CST)
> +    return NULL_TREE;
> +
> +  gcc_checking_assert (tree_to_shwi (initsize) >= TREE_STRING_LENGTH (init));
> +
>    return init;
>  }
>  
> Index: gcc/tree.c
> ===================================================================
> --- gcc/tree.c        (revision 265496)
> +++ gcc/tree.c        (working copy)

> Index: gcc/tree.h
> ===================================================================
> --- gcc/tree.h        (revision 265496)
> +++ gcc/tree.h        (working copy)
> @@ -4194,7 +4194,7 @@ extern tree build_call_expr_internal_loc_array (lo
>  extern tree maybe_build_call_expr_loc (location_t, combined_fn, tree,
>                                      int, ...);
>  extern tree build_alloca_call_expr (tree, unsigned int, HOST_WIDE_INT);
> -extern tree build_string_literal (int, const char *);
> +extern tree build_string_literal (int, const char *, tree = char_type_node);
>  
>  /* Construct various nodes representing data types.  */
There's only about a dozen calls to build_string_literal.  Instead of
defaulting the argument, just fix them.    OK with that change.  Make
sure to catch those in config/{rs6000,i386}/ and cp/

jeff

Reply via email to