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