> Am 03.01.2025 um 22:48 schrieb Jakub Jelinek <ja...@redhat.com>:
> 
> Hi!
> 
> As suggested by Richi in the PR, the following patch will fail to DCE
> allocation calls if they have constant size which is too large (over
> PTRDIFF_MAX), or for the case of calloc, if either of the arguments
> is too large (in that case in theory the call could succeed if the other
> argument is variable zero but who cares) or if both are constant and
> their product overflows or is above PTRDIFF_MAX.
> 
> This will make some pedantic conformance tests happy, though if one
> hides the size one will still need to use -fno-malloc-dce or obfuscate even
> the malloc etc. uses.  If the size is constant and too large, it isn't worth
> trying to optimize it.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Ok

Thanks,
Richard 

> 2025-01-03  Jakub Jelinek  <ja...@redhat.com>
> 
>    PR tree-optimization/118224
>    * tree-ssa-dce.cc (is_removable_allocation_p): Don't return true
>    for allocations with constant size argument larger than PTRDIFF_MAX
>    or for calloc with one of the arguments constant larger than
>    PTRDIFF_MAX or their product known constant above PTRDIFF_MAX.
>    Fix comment typos, furhter -> further and then -> than.
>    * lto-section-in.cc (lto_free_function_in_decl_state_for_node):
>    Fix comment typo, furhter -> further.
> 
>    * gcc.dg/pr118224.c: New test.
>    * c-c++-common/ubsan/vla-1.c (bar): Use noipa attribute instead
>    of noinline, noclone.
> 
> --- gcc/tree-ssa-dce.cc.jj    2025-01-02 11:23:26.890372040 +0100
> +++ gcc/tree-ssa-dce.cc    2025-01-03 20:01:33.074172650 +0100
> @@ -243,38 +243,101 @@ mark_operand_necessary (tree op)
> 
> /* Return true if STMT is a call to allocation function that can be
>    optimized out if the memory block is never used for anything else
> -   then NULL pointer check or free.
> -   If NON_NULL_CHECK is false, we can furhter assume that return value
> -   is never checked to be non-NULL. */
> +   than NULL pointer check or free.
> +   If NON_NULL_CHECK is false, we can further assume that return value
> +   is never checked to be non-NULL.
> +   Don't return true if it is called with constant size (or sizes for calloc)
> +   and the size is excessively large (larger than PTRDIFF_MAX, for calloc
> +   either argument larger than PTRDIFF_MAX or both constant and their product
> +   larger than PTRDIFF_MAX).  */
> 
> static bool
> is_removable_allocation_p (gcall *stmt, bool non_null_check)
> {
> -  tree callee = gimple_call_fndecl (stmt);
> +  int arg = -1;
> +  tree callee = gimple_call_fndecl (stmt), a1, a2;
>   if (callee != NULL_TREE
>       && fndecl_built_in_p (callee, BUILT_IN_NORMAL))
>     switch (DECL_FUNCTION_CODE (callee))
>       {
>       case BUILT_IN_MALLOC:
> +    arg = 1;
> +    goto do_malloc;
>       case BUILT_IN_ALIGNED_ALLOC:
> +    arg = 2;
> +    goto do_malloc;
>       case BUILT_IN_CALLOC:
> +    arg = 3;
> +    goto do_malloc;
>       CASE_BUILT_IN_ALLOCA:
> +    arg = 1;
> +    goto do_malloc;
>       case BUILT_IN_STRDUP:
>       case BUILT_IN_STRNDUP:
> -    return non_null_check ? flag_malloc_dce > 1 : flag_malloc_dce;
> +    arg = 0;
> +    /* FALLTHRU */
> +      do_malloc:
> +    if (non_null_check)
> +      {
> +        if (flag_malloc_dce <= 1)
> +          return false;
> +      }
> +    else if (!flag_malloc_dce)
> +      return false;
> +    break;
> 
>       case BUILT_IN_GOMP_ALLOC:
> -    return true;
> +    arg = 2;
> +    break;
> 
>       default:;
>       }
> 
> -  if (callee != NULL_TREE
> +  if (arg == -1
> +      && callee != NULL_TREE
>       && flag_allocation_dce
>       && gimple_call_from_new_or_delete (stmt)
>       && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee))
> -    return true;
> -  return false;
> +    arg = 1;
> +
> +  switch (arg)
> +    {
> +    case -1:
> +      return false;
> +    case 0:
> +      return true;
> +    case 1:
> +    case 2:
> +      if (gimple_call_num_args (stmt) < (unsigned) arg)
> +    return false;
> +      a1 = gimple_call_arg (stmt, arg - 1);
> +      if (tree_fits_uhwi_p (a1)
> +      && (tree_to_uhwi (a1)
> +          > tree_to_uhwi (TYPE_MAX_VALUE (ptrdiff_type_node))))
> +    return false;
> +      return true;
> +    case 3:
> +      if (gimple_call_num_args (stmt) < 2)
> +    return false;
> +      a1 = gimple_call_arg (stmt, 0);
> +      a2 = gimple_call_arg (stmt, 1);
> +      if (tree_fits_uhwi_p (a1)
> +      && (tree_to_uhwi (a1)
> +          > tree_to_uhwi (TYPE_MAX_VALUE (ptrdiff_type_node))))
> +    return false;
> +      if (tree_fits_uhwi_p (a2)
> +      && (tree_to_uhwi (a2)
> +          > tree_to_uhwi (TYPE_MAX_VALUE (ptrdiff_type_node))))
> +    return false;
> +      if (TREE_CODE (a1) == INTEGER_CST
> +      && TREE_CODE (a2) == INTEGER_CST
> +      && (wi::to_widest (a1) + wi::to_widest (a2)
> +          > tree_to_uhwi (TYPE_MAX_VALUE (ptrdiff_type_node))))
> +    return false;
> +      return true;
> +    default:
> +      gcc_unreachable ();
> +    }
> }
> 
> /* Return true if STMT is a conditional
> --- gcc/lto-section-in.cc.jj    2025-01-02 11:23:17.118508459 +0100
> +++ gcc/lto-section-in.cc    2025-01-03 13:49:39.589710198 +0100
> @@ -428,7 +428,7 @@ lto_free_function_in_decl_state (struct
>   ggc_free (state);
> }
> 
> -/* Free decl_states associated with NODE.  This makes it possible to furhter
> +/* Free decl_states associated with NODE.  This makes it possible to further
>    release trees needed by the NODE's body.  */
> 
> void
> --- gcc/testsuite/gcc.dg/pr118224.c.jj    2025-01-03 15:21:32.954144927 +0100
> +++ gcc/testsuite/gcc.dg/pr118224.c    2025-01-03 15:23:15.957696208 +0100
> @@ -0,0 +1,31 @@
> +/* PR tree-optimization/118224 */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -w" } */
> +
> +#include <stdlib.h>
> +
> +void
> +foo (__SIZE_TYPE__ s)
> +{
> +  if (__builtin_calloc (s, ~(__SIZE_TYPE__) 0))
> +    __builtin_abort ();
> +  if (__builtin_calloc (~(__SIZE_TYPE__) 0, s))
> +    __builtin_abort ();
> +}
> +
> +int
> +main ()
> +{
> +  if (__builtin_malloc (~(__SIZE_TYPE__) 0))
> +    __builtin_abort ();
> +#ifdef __GLIBC_PREREQ
> +#if __GLIBC_PREREQ (2, 16)
> +  /* aligned_alloc was added in glibc 2.16 */
> +  if (__builtin_aligned_alloc (32, ~(__SIZE_TYPE__) 0))
> +    __builtin_abort ();
> +#endif
> +#endif
> +  if (__builtin_calloc ((~(__SIZE_TYPE__) 0) / 2, 3))
> +    __builtin_abort ();
> +  foo (1);
> +}
> --- gcc/testsuite/c-c++-common/ubsan/vla-1.c.jj    2020-01-12 
> 11:54:37.033404055 +0100
> +++ gcc/testsuite/c-c++-common/ubsan/vla-1.c    2025-01-03 22:34:38.980852318 
> +0100
> @@ -6,7 +6,7 @@ int x = -1;
> double di = -3.2;
> V v = -6;
> 
> -static int __attribute__ ((noinline, noclone))
> +static int __attribute__ ((noipa))
> bar (void)
> {
>   return -4;
> 
>    Jakub
> 

Reply via email to