Message ID | 20210601145516.3553627-4-hjl.tools@gmail.com |
---|---|
State | New |
Headers | show |
Series | Add an internal wrapper for clone, clone2 and clone3 | expand |
They are quite similar to the non '-internal' tests, would be better to try include and reimplement the difference bits that calls the __clone_internal() intead of replicate all the tests? On 01/06/2021 11:55, H.J. Lu wrote: > --- > sysdeps/unix/sysv/linux/Makefile | 9 ++ > .../sysv/linux/tst-align-clone-internal.c | 87 +++++++++++ > sysdeps/unix/sysv/linux/tst-clone2-internal.c | 137 ++++++++++++++++++ > sysdeps/unix/sysv/linux/tst-clone3-internal.c | 99 +++++++++++++ > .../unix/sysv/linux/tst-getpid1-internal.c | 133 +++++++++++++++++ > .../sysv/linux/tst-misalign-clone-internal.c | 86 +++++++++++ > 6 files changed, 551 insertions(+) > create mode 100644 sysdeps/unix/sysv/linux/tst-align-clone-internal.c > create mode 100644 sysdeps/unix/sysv/linux/tst-clone2-internal.c > create mode 100644 sysdeps/unix/sysv/linux/tst-clone3-internal.c > create mode 100644 sysdeps/unix/sysv/linux/tst-getpid1-internal.c > create mode 100644 sysdeps/unix/sysv/linux/tst-misalign-clone-internal.c > > diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile > index 9469868bce..214b912921 100644 > --- a/sysdeps/unix/sysv/linux/Makefile > +++ b/sysdeps/unix/sysv/linux/Makefile > @@ -118,6 +118,15 @@ endif > > tests-internal += tst-sigcontext-get_pc > > +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_* Ok. > diff --git a/sysdeps/unix/sysv/linux/tst-align-clone-internal.c b/sysdeps/unix/sysv/linux/tst-align-clone-internal.c > new file mode 100644 > index 0000000000..6c3631f3db > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/tst-align-clone-internal.c > @@ -0,0 +1,87 @@ > +/* 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> > + > +static int > +f (void *arg) > +{ > + bool ok = true; > + > + puts ("in f"); > + > + if (TEST_STACK_ALIGN ()) > + ok = false; > + > + return ok ? 0 : 1; > +} Maybe: statit int f (void *arg) { return TEST_STACK_ALIGN () ? 0 : 1; } > + > +static int > +do_test (void) > +{ > + bool ok = true; > + > + puts ("in main"); > + > + if (TEST_STACK_ALIGN ()) > + ok = false; > + Maybe ok = TEST_STACK_ALIGN (); But I think this does not really add much, so I think it would be better to: 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); > + if (p == -1) > + { > + printf("clone failed: %m\n"); > + return 1; > + } Use TEST_VERIFY here: TEST_VERIFY (p != -1); > + > + 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) > + ok = false; TEST_VERIFY (WIFEXITED (status)); TEST_COMPARE (WEXITSTATUS (status), 0); > + > + return ok ? 0 : 1; > +} > + > +#include <support/test-driver.c> > diff --git a/sysdeps/unix/sysv/linux/tst-clone2-internal.c b/sysdeps/unix/sysv/linux/tst-clone2-internal.c > new file mode 100644 > index 0000000000..b8917fe713 > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/tst-clone2-internal.c > @@ -0,0 +1,137 @@ > +/* 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]); > + > + int ret = 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); > + if (!WIFEXITED (e)) > + { > + if (WIFSIGNALED (e)) > + printf ("died from signal %s\n", strsignal (WTERMSIG (e))); > + else > + puts ("did not terminate correctly"); > + exit (EXIT_FAILURE); > + } > + if (WEXITSTATUS (e) != 0) > + FAIL_EXIT1 ("exit code %d", WEXITSTATUS (e)); TEST_VERIFY (WIFEXITED (status)); TEST_COMPARE (WEXITSTATUS (status), 0); > + > + return ret; > +} > + > +#include <support/test-driver.c> > diff --git a/sysdeps/unix/sysv/linux/tst-clone3-internal.c b/sysdeps/unix/sysv/linux/tst-clone3-internal.c > new file mode 100644 > index 0000000000..2bdbc571e6 > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/tst-clone3-internal.c > @@ -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> > diff --git a/sysdeps/unix/sysv/linux/tst-getpid1-internal.c b/sysdeps/unix/sysv/linux/tst-getpid1-internal.c > new file mode 100644 > index 0000000000..ee69e52401 > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/tst-getpid1-internal.c > @@ -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> Ok. > diff --git a/sysdeps/unix/sysv/linux/tst-misalign-clone-internal.c b/sysdeps/unix/sysv/linux/tst-misalign-clone-internal.c > new file mode 100644 > index 0000000000..6df5fd2cbc > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/tst-misalign-clone-internal.c > @@ -0,0 +1,86 @@ > +/* 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) > +{ > + bool ok = true; > + > + puts ("in f"); > + > + if (TEST_STACK_ALIGN ()) > + ok = false; > + > + return ok ? 0 : 1; > +} > + > +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); > + if (!WIFEXITED (e)) > + { > + if (WIFSIGNALED (e)) > + printf ("died from signal %s\n", strsignal (WTERMSIG (e))); > + FAIL_EXIT1 ("process did not terminate correctly"); > + } > + > + if (WEXITSTATUS (e) != 0) > + FAIL_EXIT1 ("exit code %d", WEXITSTATUS (e)); > + > + return 0; > +} > + > +#include <support/test-driver.c> >
On Tue, Jul 13, 2021 at 12:33 PM Adhemerval Zanella <adhemerval.zanella@linaro.org> wrote: > > They are quite similar to the non '-internal' tests, would be better to try > include and reimplement the difference bits that calls the __clone_internal() > intead of replicate all the tests? I'd like to test __clone_internal separately and leave the existing clone tests alone. > On 01/06/2021 11:55, H.J. Lu wrote: > > --- > > sysdeps/unix/sysv/linux/Makefile | 9 ++ > > .../sysv/linux/tst-align-clone-internal.c | 87 +++++++++++ > > sysdeps/unix/sysv/linux/tst-clone2-internal.c | 137 ++++++++++++++++++ > > sysdeps/unix/sysv/linux/tst-clone3-internal.c | 99 +++++++++++++ > > .../unix/sysv/linux/tst-getpid1-internal.c | 133 +++++++++++++++++ > > .../sysv/linux/tst-misalign-clone-internal.c | 86 +++++++++++ > > 6 files changed, 551 insertions(+) > > create mode 100644 sysdeps/unix/sysv/linux/tst-align-clone-internal.c > > create mode 100644 sysdeps/unix/sysv/linux/tst-clone2-internal.c > > create mode 100644 sysdeps/unix/sysv/linux/tst-clone3-internal.c > > create mode 100644 sysdeps/unix/sysv/linux/tst-getpid1-internal.c > > create mode 100644 sysdeps/unix/sysv/linux/tst-misalign-clone-internal.c > > > > diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile > > index 9469868bce..214b912921 100644 > > --- a/sysdeps/unix/sysv/linux/Makefile > > +++ b/sysdeps/unix/sysv/linux/Makefile > > @@ -118,6 +118,15 @@ endif > > > > tests-internal += tst-sigcontext-get_pc > > > > +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_* > > Ok. > > > diff --git a/sysdeps/unix/sysv/linux/tst-align-clone-internal.c b/sysdeps/unix/sysv/linux/tst-align-clone-internal.c > > new file mode 100644 > > index 0000000000..6c3631f3db > > --- /dev/null > > +++ b/sysdeps/unix/sysv/linux/tst-align-clone-internal.c > > @@ -0,0 +1,87 @@ > > +/* 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> > > + > > +static int > > +f (void *arg) > > +{ > > + bool ok = true; > > + > > + puts ("in f"); > > + > > + if (TEST_STACK_ALIGN ()) > > + ok = false; > > + > > + return ok ? 0 : 1; > > +} > > Maybe: > > statit int > f (void *arg) > { > return TEST_STACK_ALIGN () ? 0 : 1; > } Fixed. > > + > > +static int > > +do_test (void) > > +{ > > + bool ok = true; > > + > > + puts ("in main"); > > + > > + if (TEST_STACK_ALIGN ()) > > + ok = false; > > + > > Maybe > > ok = TEST_STACK_ALIGN (); > > But I think this does not really add much, so I think it would be better > to: > > if (! TEST_STACK_ALIGN ()) > FAIL_EXIT1 ("stack alignment failed"); Fixed. > > +#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); > > + if (p == -1) > > + { > > + printf("clone failed: %m\n"); > > + return 1; > > + } > > Use TEST_VERIFY here: > > TEST_VERIFY (p != -1); Fixed. > > + > > + 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) > > + ok = false; > > TEST_VERIFY (WIFEXITED (status)); > TEST_COMPARE (WEXITSTATUS (status), 0); Fixed. > > + > > + return ok ? 0 : 1; > > +} > > + > > +#include <support/test-driver.c> > > diff --git a/sysdeps/unix/sysv/linux/tst-clone2-internal.c b/sysdeps/unix/sysv/linux/tst-clone2-internal.c > > new file mode 100644 > > index 0000000000..b8917fe713 > > --- /dev/null > > +++ b/sysdeps/unix/sysv/linux/tst-clone2-internal.c > > @@ -0,0 +1,137 @@ > > +/* 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]); > > + > > + int ret = 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); > > + if (!WIFEXITED (e)) > > + { > > + if (WIFSIGNALED (e)) > > + printf ("died from signal %s\n", strsignal (WTERMSIG (e))); > > + else > > + puts ("did not terminate correctly"); > > + exit (EXIT_FAILURE); > > + } > > + if (WEXITSTATUS (e) != 0) > > + FAIL_EXIT1 ("exit code %d", WEXITSTATUS (e)); > > TEST_VERIFY (WIFEXITED (status)); > TEST_COMPARE (WEXITSTATUS (status), 0); Fixed. > > + > > + return ret; > > +} > > + > > +#include <support/test-driver.c> > > diff --git a/sysdeps/unix/sysv/linux/tst-clone3-internal.c b/sysdeps/unix/sysv/linux/tst-clone3-internal.c > > new file mode 100644 > > index 0000000000..2bdbc571e6 > > --- /dev/null > > +++ b/sysdeps/unix/sysv/linux/tst-clone3-internal.c > > @@ -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> > > diff --git a/sysdeps/unix/sysv/linux/tst-getpid1-internal.c b/sysdeps/unix/sysv/linux/tst-getpid1-internal.c > > new file mode 100644 > > index 0000000000..ee69e52401 > > --- /dev/null > > +++ b/sysdeps/unix/sysv/linux/tst-getpid1-internal.c > > @@ -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> > > Ok. > > > diff --git a/sysdeps/unix/sysv/linux/tst-misalign-clone-internal.c b/sysdeps/unix/sysv/linux/tst-misalign-clone-internal.c > > new file mode 100644 > > index 0000000000..6df5fd2cbc > > --- /dev/null > > +++ b/sysdeps/unix/sysv/linux/tst-misalign-clone-internal.c > > @@ -0,0 +1,86 @@ > > +/* 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) > > +{ > > + bool ok = true; > > + > > + puts ("in f"); > > + > > + if (TEST_STACK_ALIGN ()) > > + ok = false; > > + > > + return ok ? 0 : 1; > > +} I made a similar change here. > > +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); > > + if (!WIFEXITED (e)) > > + { > > + if (WIFSIGNALED (e)) > > + printf ("died from signal %s\n", strsignal (WTERMSIG (e))); > > + FAIL_EXIT1 ("process did not terminate correctly"); > > + } > > + > > + if (WEXITSTATUS (e) != 0) > > + FAIL_EXIT1 ("exit code %d", WEXITSTATUS (e)); Likewise. > > + return 0; > > +} > > + > > +#include <support/test-driver.c> > > Here is the v9 patch. OK for master? Thanks.
On 13/07/2021 18:12, H.J. Lu wrote: > > Here is the v9 patch. OK for master? > > Thanks. > I think you forgot the attach the patch.
On Wed, Jul 14, 2021 at 6:18 AM Adhemerval Zanella <adhemerval.zanella@linaro.org> wrote: > > > > On 13/07/2021 18:12, H.J. Lu wrote: > > > > Here is the v9 patch. OK for master? > > > > Thanks. > > > > I think you forgot the attach the patch. Oops. Here is the patch.
On 14/07/2021 10:32, H.J. Lu wrote: > On Wed, Jul 14, 2021 at 6:18 AM Adhemerval Zanella > <adhemerval.zanella@linaro.org> wrote: >> >> >> >> On 13/07/2021 18:12, H.J. Lu wrote: >>> >>> Here is the v9 patch. OK for master? >>> >>> Thanks. >>> >> >> I think you forgot the attach the patch. > > Oops. Here is the patch. > LGTM, thanks. Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org> > From 1aa6b571479b0a2fb54e8455f45875b4f6b4b2d8 Mon Sep 17 00:00:00 2001 > From: "H.J. Lu" <hjl.tools@gmail.com> > Date: Fri, 14 May 2021 15:23:46 -0700 > Subject: [PATCH v9] Add static tests for __clone_internal > > --- > sysdeps/unix/sysv/linux/Makefile | 9 ++ > .../sysv/linux/tst-align-clone-internal.c | 68 +++++++++ > sysdeps/unix/sysv/linux/tst-clone2-internal.c | 126 +++++++++++++++++ > sysdeps/unix/sysv/linux/tst-clone3-internal.c | 99 +++++++++++++ > .../unix/sysv/linux/tst-getpid1-internal.c | 133 ++++++++++++++++++ > .../sysv/linux/tst-misalign-clone-internal.c | 74 ++++++++++ > 6 files changed, 509 insertions(+) > create mode 100644 sysdeps/unix/sysv/linux/tst-align-clone-internal.c > create mode 100644 sysdeps/unix/sysv/linux/tst-clone2-internal.c > create mode 100644 sysdeps/unix/sysv/linux/tst-clone3-internal.c > create mode 100644 sysdeps/unix/sysv/linux/tst-getpid1-internal.c > create mode 100644 sysdeps/unix/sysv/linux/tst-misalign-clone-internal.c > > diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile > index ed0c0d27f4..cceb16be05 100644 > --- a/sysdeps/unix/sysv/linux/Makefile > +++ b/sysdeps/unix/sysv/linux/Makefile > @@ -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_*, Ok. > diff --git a/sysdeps/unix/sysv/linux/tst-align-clone-internal.c b/sysdeps/unix/sysv/linux/tst-align-clone-internal.c > new file mode 100644 > index 0000000000..f3f5b46378 > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/tst-align-clone-internal.c > @@ -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> Ok. > diff --git a/sysdeps/unix/sysv/linux/tst-clone2-internal.c b/sysdeps/unix/sysv/linux/tst-clone2-internal.c > new file mode 100644 > index 0000000000..fd3a55158c > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/tst-clone2-internal.c > @@ -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> Ok. > diff --git a/sysdeps/unix/sysv/linux/tst-clone3-internal.c b/sysdeps/unix/sysv/linux/tst-clone3-internal.c > new file mode 100644 > index 0000000000..2bdbc571e6 > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/tst-clone3-internal.c > @@ -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> Ok. > diff --git a/sysdeps/unix/sysv/linux/tst-getpid1-internal.c b/sysdeps/unix/sysv/linux/tst-getpid1-internal.c > new file mode 100644 > index 0000000000..ee69e52401 > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/tst-getpid1-internal.c > @@ -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> Ok. > diff --git a/sysdeps/unix/sysv/linux/tst-misalign-clone-internal.c b/sysdeps/unix/sysv/linux/tst-misalign-clone-internal.c > new file mode 100644 > index 0000000000..5e34160238 > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/tst-misalign-clone-internal.c > @@ -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> > -- > 2.31.1 Ok.
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index 9469868bce..214b912921 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -118,6 +118,15 @@ endif tests-internal += tst-sigcontext-get_pc +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_* diff --git a/sysdeps/unix/sysv/linux/tst-align-clone-internal.c b/sysdeps/unix/sysv/linux/tst-align-clone-internal.c new file mode 100644 index 0000000000..6c3631f3db --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-align-clone-internal.c @@ -0,0 +1,87 @@ +/* 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> + +static int +f (void *arg) +{ + bool ok = true; + + puts ("in f"); + + if (TEST_STACK_ALIGN ()) + ok = false; + + return ok ? 0 : 1; +} + +static int +do_test (void) +{ + bool ok = true; + + puts ("in main"); + + if (TEST_STACK_ALIGN ()) + ok = false; + +#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); + if (p == -1) + { + printf("clone failed: %m\n"); + return 1; + } + + 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) + ok = false; + + return ok ? 0 : 1; +} + +#include <support/test-driver.c> diff --git a/sysdeps/unix/sysv/linux/tst-clone2-internal.c b/sysdeps/unix/sysv/linux/tst-clone2-internal.c new file mode 100644 index 0000000000..b8917fe713 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-clone2-internal.c @@ -0,0 +1,137 @@ +/* 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]); + + int ret = 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); + if (!WIFEXITED (e)) + { + if (WIFSIGNALED (e)) + printf ("died from signal %s\n", strsignal (WTERMSIG (e))); + else + puts ("did not terminate correctly"); + exit (EXIT_FAILURE); + } + if (WEXITSTATUS (e) != 0) + FAIL_EXIT1 ("exit code %d", WEXITSTATUS (e)); + + return ret; +} + +#include <support/test-driver.c> diff --git a/sysdeps/unix/sysv/linux/tst-clone3-internal.c b/sysdeps/unix/sysv/linux/tst-clone3-internal.c new file mode 100644 index 0000000000..2bdbc571e6 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-clone3-internal.c @@ -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> diff --git a/sysdeps/unix/sysv/linux/tst-getpid1-internal.c b/sysdeps/unix/sysv/linux/tst-getpid1-internal.c new file mode 100644 index 0000000000..ee69e52401 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-getpid1-internal.c @@ -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> diff --git a/sysdeps/unix/sysv/linux/tst-misalign-clone-internal.c b/sysdeps/unix/sysv/linux/tst-misalign-clone-internal.c new file mode 100644 index 0000000000..6df5fd2cbc --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-misalign-clone-internal.c @@ -0,0 +1,86 @@ +/* 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) +{ + bool ok = true; + + puts ("in f"); + + if (TEST_STACK_ALIGN ()) + ok = false; + + return ok ? 0 : 1; +} + +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); + if (!WIFEXITED (e)) + { + if (WIFSIGNALED (e)) + printf ("died from signal %s\n", strsignal (WTERMSIG (e))); + FAIL_EXIT1 ("process did not terminate correctly"); + } + + if (WEXITSTATUS (e) != 0) + FAIL_EXIT1 ("exit code %d", WEXITSTATUS (e)); + + return 0; +} + +#include <support/test-driver.c>