mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-09 23:00:07 +00:00
Add static tests for __clone_internal
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
This commit is contained in:
parent
24c78e2c75
commit
84d40d702f
@ -139,6 +139,15 @@ tests-time64 += \
|
||||
tst-sigtimedwait-time64 \
|
||||
tst-timerfd-time64 \
|
||||
|
||||
tests-clone-internal = \
|
||||
tst-align-clone-internal \
|
||||
tst-clone2-internal \
|
||||
tst-clone3-internal \
|
||||
tst-getpid1-internal \
|
||||
tst-misalign-clone-internal
|
||||
tests-internal += $(tests-clone-internal)
|
||||
tests-static += $(tests-clone-internal)
|
||||
|
||||
CFLAGS-tst-sigcontext-get_pc.c = -fasynchronous-unwind-tables
|
||||
|
||||
# Generate the list of SYS_* macros for the system calls (__NR_*
|
||||
|
68
sysdeps/unix/sysv/linux/tst-align-clone-internal.c
Normal file
68
sysdeps/unix/sysv/linux/tst-align-clone-internal.c
Normal file
@ -0,0 +1,68 @@
|
||||
/* Verify that the clone child stack is properly aligned.
|
||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <sched.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <tst-stack-align.h>
|
||||
#include <clone_internal.h>
|
||||
#include <support/xunistd.h>
|
||||
#include <support/check.h>
|
||||
|
||||
static int
|
||||
f (void *arg)
|
||||
{
|
||||
puts ("in f");
|
||||
|
||||
return TEST_STACK_ALIGN () ? 1 : 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
puts ("in main");
|
||||
|
||||
if (TEST_STACK_ALIGN ())
|
||||
FAIL_EXIT1 ("stack alignment failed");
|
||||
|
||||
#ifdef __ia64__
|
||||
# define STACK_SIZE 256 * 1024
|
||||
#else
|
||||
# define STACK_SIZE 128 * 1024
|
||||
#endif
|
||||
char st[STACK_SIZE] __attribute__ ((aligned));
|
||||
struct clone_args clone_args =
|
||||
{
|
||||
.stack = (uintptr_t) st,
|
||||
.stack_size = sizeof (st),
|
||||
};
|
||||
pid_t p = __clone_internal (&clone_args, f, 0);
|
||||
TEST_VERIFY (p != -1);
|
||||
|
||||
int e;
|
||||
xwaitpid (p, &e, __WCLONE);
|
||||
TEST_VERIFY (WIFEXITED (e));
|
||||
TEST_COMPARE (WEXITSTATUS (e), 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
126
sysdeps/unix/sysv/linux/tst-clone2-internal.c
Normal file
126
sysdeps/unix/sysv/linux/tst-clone2-internal.c
Normal file
@ -0,0 +1,126 @@
|
||||
/* Test if CLONE_VM does not change pthread pid/tid field (BZ #19957)
|
||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <clone_internal.h>
|
||||
#include <support/xunistd.h>
|
||||
#include <support/check.h>
|
||||
|
||||
static int sig;
|
||||
static int pipefd[2];
|
||||
|
||||
static int
|
||||
f (void *a)
|
||||
{
|
||||
close (pipefd[0]);
|
||||
|
||||
pid_t ppid = getppid ();
|
||||
pid_t pid = getpid ();
|
||||
pid_t tid = gettid ();
|
||||
|
||||
if (write (pipefd[1], &ppid, sizeof ppid) != sizeof (ppid))
|
||||
FAIL_EXIT1 ("write ppid failed\n");
|
||||
if (write (pipefd[1], &pid, sizeof pid) != sizeof (pid))
|
||||
FAIL_EXIT1 ("write pid failed\n");
|
||||
if (write (pipefd[1], &tid, sizeof tid) != sizeof (tid))
|
||||
FAIL_EXIT1 ("write tid failed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
sig = SIGRTMIN;
|
||||
sigset_t ss;
|
||||
sigemptyset (&ss);
|
||||
sigaddset (&ss, sig);
|
||||
if (sigprocmask (SIG_BLOCK, &ss, NULL) != 0)
|
||||
FAIL_EXIT1 ("sigprocmask failed: %m");
|
||||
|
||||
if (pipe2 (pipefd, O_CLOEXEC))
|
||||
FAIL_EXIT1 ("pipe failed: %m");
|
||||
|
||||
#ifdef __ia64__
|
||||
# define STACK_SIZE 256 * 1024
|
||||
#else
|
||||
# define STACK_SIZE 128 * 1024
|
||||
#endif
|
||||
char st[STACK_SIZE] __attribute__ ((aligned));
|
||||
struct clone_args clone_args =
|
||||
{
|
||||
.stack = (uintptr_t) st,
|
||||
.stack_size = sizeof (st),
|
||||
};
|
||||
pid_t p = __clone_internal (&clone_args, f, 0);
|
||||
|
||||
close (pipefd[1]);
|
||||
|
||||
if (p == -1)
|
||||
FAIL_EXIT1("clone failed: %m");
|
||||
|
||||
pid_t ppid, pid, tid;
|
||||
if (read (pipefd[0], &ppid, sizeof pid) != sizeof pid)
|
||||
{
|
||||
kill (p, SIGKILL);
|
||||
FAIL_EXIT1 ("read ppid failed: %m");
|
||||
}
|
||||
if (read (pipefd[0], &pid, sizeof pid) != sizeof pid)
|
||||
{
|
||||
kill (p, SIGKILL);
|
||||
FAIL_EXIT1 ("read pid failed: %m");
|
||||
}
|
||||
if (read (pipefd[0], &tid, sizeof tid) != sizeof tid)
|
||||
{
|
||||
kill (p, SIGKILL);
|
||||
FAIL_EXIT1 ("read tid failed: %m");
|
||||
}
|
||||
|
||||
close (pipefd[0]);
|
||||
|
||||
pid_t own_pid = getpid ();
|
||||
pid_t own_tid = syscall (__NR_gettid);
|
||||
|
||||
/* Some sanity checks for clone syscall: returned ppid should be current
|
||||
pid and both returned tid/pid should be different from current one. */
|
||||
if ((ppid != own_pid) || (pid == own_pid) || (tid == own_tid))
|
||||
FAIL_RET ("ppid=%i pid=%i tid=%i | own_pid=%i own_tid=%i",
|
||||
(int)ppid, (int)pid, (int)tid, (int)own_pid, (int)own_tid);
|
||||
|
||||
int e;
|
||||
xwaitpid (p, &e, __WCLONE);
|
||||
TEST_VERIFY (WIFEXITED (e));
|
||||
TEST_COMPARE (WEXITSTATUS (e), 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
99
sysdeps/unix/sysv/linux/tst-clone3-internal.c
Normal file
99
sysdeps/unix/sysv/linux/tst-clone3-internal.c
Normal file
@ -0,0 +1,99 @@
|
||||
/* Check if clone (CLONE_THREAD) does not call exit_group (BZ #21512)
|
||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <string.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <linux/futex.h>
|
||||
#include <support/check.h>
|
||||
#include <stdatomic.h>
|
||||
#include <clone_internal.h>
|
||||
|
||||
/* Test if clone call with CLONE_THREAD does not call exit_group. The 'f'
|
||||
function returns '1', which will be used by clone thread to call the
|
||||
'exit' syscall directly. If _exit is used instead, exit_group will be
|
||||
used and thus the thread group will finish with return value of '1'
|
||||
(where '2' from main thread is expected.). */
|
||||
|
||||
static int
|
||||
f (void *a)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Futex wait for TID argument, similar to pthread_join internal
|
||||
implementation. */
|
||||
#define wait_tid(ctid_ptr, ctid_val) \
|
||||
do { \
|
||||
__typeof (*(ctid_ptr)) __tid; \
|
||||
/* We need acquire MO here so that we synchronize with the \
|
||||
kernel's store to 0 when the clone terminates. */ \
|
||||
while ((__tid = atomic_load_explicit (ctid_ptr, \
|
||||
memory_order_acquire)) != 0) \
|
||||
futex_wait (ctid_ptr, ctid_val); \
|
||||
} while (0)
|
||||
|
||||
static inline int
|
||||
futex_wait (int *futexp, int val)
|
||||
{
|
||||
#ifdef __NR_futex
|
||||
return syscall (__NR_futex, futexp, FUTEX_WAIT, val);
|
||||
#else
|
||||
return syscall (__NR_futex_time64, futexp, FUTEX_WAIT, val);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
char st[1024] __attribute__ ((aligned));
|
||||
int clone_flags = CLONE_THREAD;
|
||||
/* Minimum required flags to used along with CLONE_THREAD. */
|
||||
clone_flags |= CLONE_VM | CLONE_SIGHAND;
|
||||
/* We will used ctid to call on futex to wait for thread exit. */
|
||||
clone_flags |= CLONE_CHILD_CLEARTID;
|
||||
/* Initialize with a known value. ctid is set to zero by the kernel after the
|
||||
cloned thread has exited. */
|
||||
#define CTID_INIT_VAL 1
|
||||
pid_t ctid = CTID_INIT_VAL;
|
||||
pid_t tid;
|
||||
|
||||
struct clone_args clone_args =
|
||||
{
|
||||
.flags = clone_flags & ~CSIGNAL,
|
||||
.exit_signal = clone_flags & CSIGNAL,
|
||||
.stack = (uintptr_t) st,
|
||||
.stack_size = sizeof (st),
|
||||
.child_tid = (uintptr_t) &ctid,
|
||||
};
|
||||
tid = __clone_internal (&clone_args, f, NULL);
|
||||
if (tid == -1)
|
||||
FAIL_EXIT1 ("clone failed: %m");
|
||||
|
||||
wait_tid (&ctid, CTID_INIT_VAL);
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
#define EXPECTED_STATUS 2
|
||||
#include <support/test-driver.c>
|
133
sysdeps/unix/sysv/linux/tst-getpid1-internal.c
Normal file
133
sysdeps/unix/sysv/linux/tst-getpid1-internal.c
Normal file
@ -0,0 +1,133 @@
|
||||
/* Verify that the parent pid is unchanged by __clone_internal.
|
||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <clone_internal.h>
|
||||
#include <support/xunistd.h>
|
||||
|
||||
#ifndef TEST_CLONE_FLAGS
|
||||
#define TEST_CLONE_FLAGS 0
|
||||
#endif
|
||||
|
||||
static int sig;
|
||||
|
||||
static int
|
||||
f (void *a)
|
||||
{
|
||||
puts ("in f");
|
||||
union sigval sival;
|
||||
sival.sival_int = getpid ();
|
||||
printf ("pid = %d\n", sival.sival_int);
|
||||
if (sigqueue (getppid (), sig, sival) != 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
int mypid = getpid ();
|
||||
|
||||
sig = SIGRTMIN;
|
||||
sigset_t ss;
|
||||
sigemptyset (&ss);
|
||||
sigaddset (&ss, sig);
|
||||
if (sigprocmask (SIG_BLOCK, &ss, NULL) != 0)
|
||||
{
|
||||
printf ("sigprocmask failed: %m\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef __ia64__
|
||||
# define STACK_SIZE 256 * 1024
|
||||
#else
|
||||
# define STACK_SIZE 128 * 1024
|
||||
#endif
|
||||
char st[STACK_SIZE] __attribute__ ((aligned));
|
||||
struct clone_args clone_args =
|
||||
{
|
||||
.flags = TEST_CLONE_FLAGS & ~CSIGNAL,
|
||||
.exit_signal = TEST_CLONE_FLAGS & CSIGNAL,
|
||||
.stack = (uintptr_t) st,
|
||||
.stack_size = sizeof (st),
|
||||
};
|
||||
pid_t p = __clone_internal (&clone_args, f, 0);
|
||||
if (p == -1)
|
||||
{
|
||||
printf("clone failed: %m\n");
|
||||
return 1;
|
||||
}
|
||||
printf ("new thread: %d\n", (int) p);
|
||||
|
||||
siginfo_t si;
|
||||
do
|
||||
if (sigwaitinfo (&ss, &si) < 0)
|
||||
{
|
||||
printf("sigwaitinfo failed: %m\n");
|
||||
kill (p, SIGKILL);
|
||||
return 1;
|
||||
}
|
||||
while (si.si_signo != sig || si.si_code != SI_QUEUE);
|
||||
|
||||
int e;
|
||||
xwaitpid (p, &e, __WCLONE);
|
||||
if (!WIFEXITED (e))
|
||||
{
|
||||
if (WIFSIGNALED (e))
|
||||
printf ("died from signal %s\n", strsignal (WTERMSIG (e)));
|
||||
else
|
||||
puts ("did not terminate correctly");
|
||||
return 1;
|
||||
}
|
||||
if (WEXITSTATUS (e) != 0)
|
||||
{
|
||||
printf ("exit code %d\n", WEXITSTATUS (e));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (si.si_int != (int) p)
|
||||
{
|
||||
printf ("expected PID %d, got si_int %d\n", (int) p, si.si_int);
|
||||
kill (p, SIGKILL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (si.si_pid != p)
|
||||
{
|
||||
printf ("expected PID %d, got si_pid %d\n", (int) p, (int) si.si_pid);
|
||||
kill (p, SIGKILL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (getpid () != mypid)
|
||||
{
|
||||
puts ("my PID changed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
74
sysdeps/unix/sysv/linux/tst-misalign-clone-internal.c
Normal file
74
sysdeps/unix/sysv/linux/tst-misalign-clone-internal.c
Normal file
@ -0,0 +1,74 @@
|
||||
/* Verify that __clone_internal properly aligns the child stack.
|
||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <sched.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <libc-pointer-arith.h>
|
||||
#include <tst-stack-align.h>
|
||||
#include <clone_internal.h>
|
||||
#include <support/xunistd.h>
|
||||
#include <support/check.h>
|
||||
|
||||
static int
|
||||
check_stack_alignment (void *arg)
|
||||
{
|
||||
puts ("in f");
|
||||
|
||||
return TEST_STACK_ALIGN () ? 1 : 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
puts ("in do_test");
|
||||
|
||||
if (TEST_STACK_ALIGN ())
|
||||
FAIL_EXIT1 ("stack isn't aligned\n");
|
||||
|
||||
#ifdef __ia64__
|
||||
# define STACK_SIZE (256 * 1024)
|
||||
#else
|
||||
# define STACK_SIZE (128 * 1024)
|
||||
#endif
|
||||
char st[STACK_SIZE + 1];
|
||||
/* NB: Align child stack to 1 byte. */
|
||||
char *stack = PTR_ALIGN_UP (&st[0], 2) + 1;
|
||||
struct clone_args clone_args =
|
||||
{
|
||||
.stack = (uintptr_t) stack,
|
||||
.stack_size = STACK_SIZE,
|
||||
};
|
||||
pid_t p = __clone_internal (&clone_args, check_stack_alignment, 0);
|
||||
|
||||
/* Clone must not fail. */
|
||||
TEST_VERIFY_EXIT (p != -1);
|
||||
|
||||
int e;
|
||||
xwaitpid (p, &e, __WCLONE);
|
||||
TEST_VERIFY (WIFEXITED (e));
|
||||
TEST_COMPARE (WEXITSTATUS (e), 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
Loading…
Reference in New Issue
Block a user