forked from bminor/glibc
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add static tests for __clone_internal
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
- Loading branch information
Showing
6 changed files
with
509 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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> |
Oops, something went wrong.