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