> 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
>