d8307d
commit a55e109709af55e6ed67d3f9536cac5d929c982e
d8307d
Author: Carlos O'Donell <carlos@redhat.com>
d8307d
Date:   Wed Sep 5 01:16:42 2018 -0400
d8307d
d8307d
    Fix tst-setcontext9 for optimized small stacks.
d8307d
    
d8307d
    If the compiler reduces the stack usage in function f1 before calling
d8307d
    into function f2, then when we swapcontext back to f1 and continue
d8307d
    execution we may overwrite registers that were spilled to the stack
d8307d
    while f2 was executing.  Later when we return to f2 the corrupt
d8307d
    registers will be reloaded from the stack and the test will crash.  This
d8307d
    was most commonly observed on i686 with __x86.get_pc_thunk.dx and
d8307d
    needing to save and restore $edx.  Overall i686 has few registers and
d8307d
    the spilling to the stack is bound to happen, therefore the solution to
d8307d
    making this test robust is to split function f1 into two parts f1a and
d8307d
    f1b, and allocate f1b it's own stack such that subsequent execution does
d8307d
    not overwrite the stack in use by function f2.
d8307d
    
d8307d
    Tested on i686 and x86_64.
d8307d
    
d8307d
    Signed-off-by: Carlos O'Donell <carlos@redhat.com>
d8307d
    (cherry picked from commit 791b350dc725545e3f9b5db0f97ebdbc60c9735f)
d8307d
d8307d
diff --git a/stdlib/tst-setcontext9.c b/stdlib/tst-setcontext9.c
d8307d
index 4636ce9030fa38a7..db8355766ca7b906 100644
d8307d
--- a/stdlib/tst-setcontext9.c
d8307d
+++ b/stdlib/tst-setcontext9.c
d8307d
@@ -41,26 +41,55 @@ f2 (void)
d8307d
 }
d8307d
 
d8307d
 static void
d8307d
-f1 (void)
d8307d
+f1b (void)
d8307d
 {
d8307d
-  puts ("start f1");
d8307d
-  if (getcontext (&ctx[2]) != 0)
d8307d
-    {
d8307d
-      printf ("%s: getcontext: %m\n", __FUNCTION__);
d8307d
-      exit (EXIT_FAILURE);
d8307d
-    }
d8307d
   if (done)
d8307d
     {
d8307d
-      puts ("set context in f1");
d8307d
+      puts ("set context in f1b");
d8307d
       if (setcontext (&ctx[3]) != 0)
d8307d
 	{
d8307d
 	  printf ("%s: setcontext: %m\n", __FUNCTION__);
d8307d
 	  exit (EXIT_FAILURE);
d8307d
 	}
d8307d
     }
d8307d
+  exit (EXIT_FAILURE);
d8307d
+}
d8307d
+
d8307d
+static void
d8307d
+f1a (void)
d8307d
+{
d8307d
+  char st2[32768];
d8307d
+  puts ("start f1a");
d8307d
+  if (getcontext (&ctx[2]) != 0)
d8307d
+    {
d8307d
+      printf ("%s: getcontext: %m\n", __FUNCTION__);
d8307d
+      exit (EXIT_FAILURE);
d8307d
+    }
d8307d
+  ctx[2].uc_stack.ss_sp = st2;
d8307d
+  ctx[2].uc_stack.ss_size = sizeof st2;
d8307d
+  ctx[2].uc_link = &ctx[0];
d8307d
+  makecontext (&ctx[2], (void (*) (void)) f1b, 0);
d8307d
   f2 ();
d8307d
 }
d8307d
 
d8307d
+/* The execution path through the test looks like this:
d8307d
+   do_test (call)
d8307d
+   -> "making contexts"
d8307d
+   -> "swap contexts"
d8307d
+   f1a (via swapcontext to ctx[1], with alternate stack)
d8307d
+   -> "start f1a"
d8307d
+   f2 (call)
d8307d
+   -> "swap contexts in f2"
d8307d
+   f1b (via swapcontext to ctx[2], with alternate stack)
d8307d
+   -> "set context in f1b"
d8307d
+   do_test (via setcontext to ctx[3], main stack)
d8307d
+   -> "setcontext"
d8307d
+   f2 (via setcontext to ctx[4], with alternate stack)
d8307d
+   -> "end f2"
d8307d
+
d8307d
+   We must use an alternate stack for f1b, because if we don't then the
d8307d
+   result of executing an earlier caller may overwrite registers
d8307d
+   spilled to the stack in f2.  */
d8307d
 static int
d8307d
 do_test (void)
d8307d
 {
d8307d
@@ -79,7 +108,7 @@ do_test (void)
d8307d
   ctx[1].uc_stack.ss_sp = st1;
d8307d
   ctx[1].uc_stack.ss_size = sizeof st1;
d8307d
   ctx[1].uc_link = &ctx[0];
d8307d
-  makecontext (&ctx[1], (void (*) (void)) f1, 0);
d8307d
+  makecontext (&ctx[1], (void (*) (void)) f1a, 0);
d8307d
   puts ("swap contexts");
d8307d
   if (swapcontext (&ctx[3], &ctx[1]) != 0)
d8307d
     {