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