mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-27 11:43:34 +08:00
S390: Do not clobber r7 in clone [BZ #31402]
Starting with commite57d8fc97b
"S390: Always use svc 0" clone clobbers the call-saved register r7 in error case: function or stack is NULL. This patch restores the saved registers also in the error case. Furthermore the existing test misc/tst-clone is extended to check all error cases and that clone does not clobber registers in this error case. (cherry picked from commit02782fd128
) Note: Added ia64 __clone2 call to tst-clone.c.
This commit is contained in:
parent
506e47da1d
commit
ee4806e978
@ -53,6 +53,7 @@ ENTRY(__clone)
|
||||
br %r14
|
||||
error:
|
||||
lhi %r2,-EINVAL
|
||||
lm %r6,%r7,24(%r15) /* Load registers. */
|
||||
j SYSCALL_ERROR_LABEL
|
||||
PSEUDO_END (__clone)
|
||||
|
||||
|
@ -54,6 +54,7 @@ ENTRY(__clone)
|
||||
br %r14
|
||||
error:
|
||||
lghi %r2,-EINVAL
|
||||
lmg %r6,%r7,48(%r15) /* Restore registers. */
|
||||
jg SYSCALL_ERROR_LABEL
|
||||
PSEUDO_END (__clone)
|
||||
|
||||
|
@ -16,12 +16,16 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* BZ #2386 */
|
||||
/* BZ #2386, BZ #31402 */
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#include <stackinfo.h> /* For _STACK_GROWS_{UP,DOWN}. */
|
||||
#include <support/check.h>
|
||||
|
||||
volatile unsigned v = 0xdeadbeef;
|
||||
|
||||
#ifdef __ia64__
|
||||
extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base,
|
||||
@ -35,26 +39,72 @@ int child_fn(void *arg)
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
__attribute__((noinline))
|
||||
do_clone (int (*fn)(void *), void *stack)
|
||||
{
|
||||
int result;
|
||||
unsigned int a = v;
|
||||
unsigned int b = v;
|
||||
unsigned int c = v;
|
||||
unsigned int d = v;
|
||||
unsigned int e = v;
|
||||
unsigned int f = v;
|
||||
unsigned int g = v;
|
||||
unsigned int h = v;
|
||||
unsigned int i = v;
|
||||
unsigned int j = v;
|
||||
unsigned int k = v;
|
||||
unsigned int l = v;
|
||||
unsigned int m = v;
|
||||
unsigned int n = v;
|
||||
unsigned int o = v;
|
||||
|
||||
#ifdef __ia64__
|
||||
result = __clone2 (child_fn, NULL, 0, 0, NULL, NULL, NULL);
|
||||
result = __clone2 (fn, stack, stack != NULL ? 128 * 1024 : 0, 0, NULL, NULL,
|
||||
NULL);
|
||||
#else
|
||||
result = clone (child_fn, NULL, 0, NULL);
|
||||
result = clone (fn, stack, 0, NULL);
|
||||
#endif
|
||||
|
||||
if (errno != EINVAL || result != -1)
|
||||
{
|
||||
printf ("FAIL: clone()=%d (wanted -1) errno=%d (wanted %d)\n",
|
||||
result, errno, EINVAL);
|
||||
return 1;
|
||||
}
|
||||
/* Check that clone does not clobber call-saved registers. */
|
||||
TEST_VERIFY (a == v && b == v && c == v && d == v && e == v && f == v
|
||||
&& g == v && h == v && i == v && j == v && k == v && l == v
|
||||
&& m == v && n == v && o == v);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
__attribute__((noinline))
|
||||
do_test_single (int (*fn)(void *), void *stack)
|
||||
{
|
||||
printf ("%s (fn=%p, stack=%p)\n", __FUNCTION__, fn, stack);
|
||||
errno = 0;
|
||||
|
||||
int result = do_clone (fn, stack);
|
||||
|
||||
TEST_COMPARE (errno, EINVAL);
|
||||
TEST_COMPARE (result, -1);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
char st[128 * 1024] __attribute__ ((aligned));
|
||||
void *stack = NULL;
|
||||
#if defined __ia64__ || _STACK_GROWS_UP
|
||||
stack = st;
|
||||
#elif _STACK_GROWS_DOWN
|
||||
stack = st + sizeof (st);
|
||||
#else
|
||||
# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
|
||||
#endif
|
||||
|
||||
do_test_single (child_fn, NULL);
|
||||
do_test_single (NULL, stack);
|
||||
do_test_single (NULL, NULL);
|
||||
|
||||
puts ("All OK");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
#include <support/test-driver.c>
|
||||
|
Loading…
Reference in New Issue
Block a user