Than McIntosh encountered a bug on 32-bit x86 with code that calls
alloca when using -fsplit-stack when -mno-accumulate-outgoing-args is
in effect.  When alloca is called after a function call, the arguments
are left on the stack, which can cause the stack to become misaligned.
The problem is simply that the stack-split alloca support is
implemented before calling do_pending_stack_adjust.  This patch fixes
the problem and adds a test case.  Bootstrapped and ran all tests on
x86_64-pc-linux-gnu.  Committed to mainline.

Ian

2016-10-04  Ian Lance Taylor  <i...@golang.org>

* explow.c (allocate_dynamic_stack_space): Call
do_pending_stack_adjust before handling flag_split_stack.

2016-10-04  Ian Lance Taylor  <i...@golang.org>

* gcc.dg/split-7.c: New test.
Index: gcc/explow.c
===================================================================
--- gcc/explow.c        (revision 240755)
+++ gcc/explow.c        (working copy)
@@ -1357,6 +1357,8 @@ allocate_dynamic_stack_space (rtx size,
        current_function_has_unbounded_dynamic_stack_size = 1;
     }
 
+  do_pending_stack_adjust ();
+
   final_label = NULL;
   final_target = NULL_RTX;
 
@@ -1414,8 +1416,6 @@ allocate_dynamic_stack_space (rtx size,
       emit_label (available_label);
     }
 
-  do_pending_stack_adjust ();
-
  /* We ought to be called always on the toplevel and stack ought to be aligned
     properly.  */
   gcc_assert (!(stack_pointer_delta
Index: gcc/testsuite/gcc.dg/split-7.c
===================================================================
--- gcc/testsuite/gcc.dg/split-7.c      (revision 0)
+++ gcc/testsuite/gcc.dg/split-7.c      (working copy)
@@ -0,0 +1,55 @@
+/* { dg-do run } */
+/* { dg-require-effective-target split_stack } */
+/* { dg-options "-fsplit-stack -O2" } */
+/* { dg-options "-fsplit-stack -O2 -mno-accumulate-outgoing-args" { target { { 
i?86-*-* x86_64-*-* } && ia32 } } } */
+
+/* A case that used to fail on 32-bit x86 when optimizing and not
+   using -maccumulate-args.  The stack adjustment of the alloca got
+   mixed up with the arguments pushed on the stack to the function
+   before the call of alloca.  */
+
+#include <stdlib.h>
+
+typedef struct { const char* s; int l; } s;
+
+typedef unsigned long long align16 __attribute__ ((aligned(16)));
+
+s gobats (const void *, int) __attribute__ ((noinline));
+
+s
+gobats (const void* p __attribute__ ((unused)),
+       int l __attribute__ ((unused)))
+{
+  s v;
+  v.s = 0;
+  v.l = 0;
+  return v;
+}
+
+void check_aligned (void *p) __attribute__ ((noinline));
+
+void
+check_aligned (void *p)
+{
+  if (((__SIZE_TYPE__) p & 0xf) != 0)
+    abort ();
+}
+
+void gap (void *) __attribute__ ((noinline));
+
+void gap (void *p)
+{
+  align16 a;
+  check_aligned (&a);
+}
+
+int
+main (int argc, char **argv)
+{
+  s *space;
+  gobats(0, 16);
+  space = (s *) alloca(sizeof(s) + 1);
+  *space = (s){0, 16};
+  gap(space);
+  return 0;
+}

Reply via email to