https://gcc.gnu.org/g:8d381a5e520aeebe387c6f6353357e76d489ed7f

commit r17-5257-g8d381a5e520aeebe387c6f6353357e76d489ed7f
Author: Stefan Schulze Frielinghaus <[email protected]>
Date:   Fri Oct 16 16:40:26 2026 +0200

    explow: Restore stack_pointer_delta for allocate_stack [PR114432]
    
    Function allocate_dynamic_stack_space() saves and restores
    stack_pointer_delta only if expander allocate_stack is not available.
    On s390 with -mbackchain the expander becomes available and changes
    stack_pointer_delta indirectly by calling into anti_adjust_stack()
    (as the else branch does when the expander is not available).  In that
    case nothing is saved or restored, so the altered stack_pointer_delta
    leaks.  With -fstack-check, expand_function_end() emits a function-entry
    probe through anti_adjust_stack_and_probe() which then picks up the
    leaked value.  This can be observed in reproducer pr114432-1.c where the
    entry-probe insns 47 and 50 carry wrong REG_ARGS_SIZE notes:
    
    (insn 47 2 48 2 (parallel [
                (set (reg/f:DI 15 %r15)
                    (plus:DI (reg/f:DI 15 %r15)
                        (const_int -8216 [0xffffffffffffdfe8])))
                (clobber (reg:CC 33 %cc))
            ]) "pr114432-1.c":7:1 -1
         (expr_list:REG_ARGS_SIZE (const_int 8304 [0x2070])  <--- should be 8216
            (nil)))
    ...
    (insn 50 49 3 2 (parallel [
                (set (reg/f:DI 15 %r15)
                    (plus:DI (reg/f:DI 15 %r15)
                        (const_int 8216 [0x2018])))
                (clobber (reg:CC 33 %cc))
            ]) "pr114432-1.c":7:1 -1
         (expr_list:REG_ARGS_SIZE (const_int 88 [0x58])      <--- should be 0
            (nil)))
    ...
    (insn 30 29 31 7 (set (reg/f:DI 15 %r15)
            (reg/f:DI 62 [ saved_stack.1_6 ])) -1
         (expr_list:REG_ARGS_SIZE (const_int 0 [0])          <--- ok
            (nil)))
    
    Here the constant-sized alloca with a size of 88 bytes leaks into
    REG_ARGS_SIZE (8304 = 8216 + 88).  Note, REG_ARGS_SIZE for insn 30 is
    correct since the insn restores the stack pointer after the alloca (the
    zero is hard coded in expand_stack_restore()).
    
    The entry probe, ending in insn 50, falls through into the loop head
    with the leaked 88 bytes, whereas the back edge of the loop arrives with
    0 bytes (insn 30 restores the stack).  Due to those two traces with
    differing args_sizes, args_size_undefined is set.  Because -fexceptions
    makes a call in the loop trace possibly throwing, and no insn in that
    trace sets args_size before the first throwing call,
    args_size_defined_for_eh is not set.  This renders the assert
    
      gcc_assert (!ti->args_size_undefined || ti->args_size_defined_for_eh);
    
    failing in connect_traces().
    
    Fixed by saving/restoring stack_pointer_delta for allocate_stack, too.
    
            PR middle-end/114432
    
    gcc/ChangeLog:
    
            * explow.cc (allocate_dynamic_stack_space): Save and restore
            stack_pointer_delta also if expander allocate_stack is
            available.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/s390/pr114432-1.c: New test.

Diff:
---
 gcc/explow.cc                              | 16 +++++++---------
 gcc/testsuite/gcc.target/s390/pr114432-1.c | 14 ++++++++++++++
 2 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/gcc/explow.cc b/gcc/explow.cc
index 9c7c834aaabb..6acecc701c76 100644
--- a/gcc/explow.cc
+++ b/gcc/explow.cc
@@ -1603,6 +1603,8 @@ allocate_dynamic_stack_space (rtx size, unsigned 
size_align,
   /* Don't let anti_adjust_stack emit notes.  */
   suppress_reg_args_size = true;
 
+  poly_int64 saved_stack_pointer_delta = stack_pointer_delta;
+
   /* Perform the required allocation from the stack.  Some systems do
      this differently than simply incrementing/decrementing from the
      stack pointer, such as acquiring the space by calling malloc().  */
@@ -1618,8 +1620,6 @@ allocate_dynamic_stack_space (rtx size, unsigned 
size_align,
     }
   else
     {
-      poly_int64 saved_stack_pointer_delta;
-
       if (!STACK_GROWS_DOWNWARD)
        emit_move_insn (target, force_operand (addr, target));
 
@@ -1647,8 +1647,6 @@ allocate_dynamic_stack_space (rtx size, unsigned 
size_align,
          emit_label (space_available);
        }
 
-      saved_stack_pointer_delta = stack_pointer_delta;
-
       /* If stack checking or stack clash protection is requested,
         then probe the stack while allocating space from it.  */
       if (flag_stack_check && STACK_CHECK_MOVING_SP)
@@ -1658,15 +1656,15 @@ allocate_dynamic_stack_space (rtx size, unsigned 
size_align,
       else
        anti_adjust_stack (size);
 
-      /* Even if size is constant, don't modify stack_pointer_delta.
-        The constant size alloca should preserve
-        crtl->preferred_stack_boundary alignment.  */
-      stack_pointer_delta = saved_stack_pointer_delta;
-
       if (STACK_GROWS_DOWNWARD)
        emit_move_insn (target, force_operand (addr, target));
     }
 
+  /* Even if size is constant, don't modify stack_pointer_delta.
+     The constant size alloca should preserve
+     crtl->preferred_stack_boundary alignment.  */
+  stack_pointer_delta = saved_stack_pointer_delta;
+
   suppress_reg_args_size = false;
 
   /* Finish up the split stack handling.  */
diff --git a/gcc/testsuite/gcc.target/s390/pr114432-1.c 
b/gcc/testsuite/gcc.target/s390/pr114432-1.c
new file mode 100644
index 000000000000..5e53755875f0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/pr114432-1.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fexceptions -fstack-check -mbackchain" } */
+
+void a (int *);
+int b (char *);
+void c (void)
+{
+  for (;;)
+    {
+      char d[88];
+      int e __attribute__ ((cleanup (a))) = 0;
+      b (d);
+    }
+}

Reply via email to