From patchwork Sat May 22 03:50:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "H.J. Lu" X-Patchwork-Id: 43544 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8BE5A3AAA0D2; Sat, 22 May 2021 03:50:29 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8BE5A3AAA0D2 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1621655429; bh=3k2wWbqzGUXVDwDOIivM+qYT5dZHO2761W2a27mXnn0=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=lASGHegIniM1i4Su30I7pKFktxRQCN8oUMqGfybIHdevoT58x9lttsnY7z0Ju3L0s QE8U9Xga908kiWIIpy+S7s6y+ZmRNhLy+8Gw+u019cWVCE7x34J9ZYvcR80YGoRI0U tQ1lt6jVDNPSJuSThSMPGOfFjX+zP9HObn/o5JHU= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-pl1-x636.google.com (mail-pl1-x636.google.com [IPv6:2607:f8b0:4864:20::636]) by sourceware.org (Postfix) with ESMTPS id 5C016384605A for ; Sat, 22 May 2021 03:50:24 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 5C016384605A Received: by mail-pl1-x636.google.com with SMTP id 69so11978629plc.5 for ; Fri, 21 May 2021 20:50:24 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=3k2wWbqzGUXVDwDOIivM+qYT5dZHO2761W2a27mXnn0=; b=VoAp61qS7zMV13iICOXyT0FFDIY4Ma5cuif6PoCfhQNHze3zbeweqc3DQZFo/KhfDI VVhYJRrPsLU9q0zqjYgnWajoSfXCsMaQCnOcFWBDFyTqFp1hQrN3i1CADR4ktua1nr7M S45euRE3/5XX3f8+x9BUd3FM1ZJ/ZTkDA1776GrQe3VzJIZTuD8RJB701+XZa/vn9KRR zd8QQvw/x5l5nJJuPFIgiF3W5Xk+03hv8qj1yhF3TVrCpnBkukgk+iYBJyJryYIx14Zt A+/o+o53HZegAn2mRCzw0c1ZbgWoU5VcdW4kPbJLrb1oK+qlBri7Pdq7O6G54LkIp4tc MKCw== X-Gm-Message-State: AOAM5314/iJyBm5J8sUOM5Dp6iQQ+nPQTuYuHnJUdlGdkk0uKsiuPHyq mpjRSgM/6mr1UcUbndDxKMSZD+wu9o8p2g== X-Google-Smtp-Source: ABdhPJzUafutUlItmDRFg6VPZN2FiS+fKmDpB7LpAt2JVDJX67z8MTuJ7YygnvAxbqjzJau57bytvw== X-Received: by 2002:a17:902:b408:b029:ec:e879:bbd8 with SMTP id x8-20020a170902b408b02900ece879bbd8mr15568207plr.65.1621655423427; Fri, 21 May 2021 20:50:23 -0700 (PDT) Received: from gnu-cfl-2.localdomain ([172.56.38.102]) by smtp.gmail.com with ESMTPSA id a10sm9426276pjs.39.2021.05.21.20.50.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 21 May 2021 20:50:22 -0700 (PDT) Received: from gnu-cfl-2.. (localhost [IPv6:::1]) by gnu-cfl-2.localdomain (Postfix) with ESMTP id 68BD9C04B5; Fri, 21 May 2021 20:50:18 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH v6 5/5] Add static tests for __clone_internal Date: Fri, 21 May 2021 20:50:18 -0700 Message-Id: <20210522035018.2652112-6-hjl.tools@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210522035018.2652112-1-hjl.tools@gmail.com> References: <20210522035018.2652112-1-hjl.tools@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-3035.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: "H.J. Lu via Libc-alpha" From: "H.J. Lu" Reply-To: "H.J. Lu" Cc: Florian Weimer Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" --- sysdeps/unix/sysv/linux/Makefile | 8 + .../sysv/linux/tst-align-clone-internal.c | 86 +++++++++++ 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 | 132 +++++++++++++++++ 5 files changed, 462 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 diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index 11b09345bc..9bcd38a732 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -118,6 +118,14 @@ endif tests-internal += tst-sigcontext-get_pc +tests-clone-internal = \ + tst-align-clone-internal \ + tst-clone2-internal \ + tst-clone3-internal \ + tst-getpid1-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..0e5307a033 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-align-clone-internal.c @@ -0,0 +1,86 @@ +/* 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 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..5ce091168e --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-getpid1-internal.c @@ -0,0 +1,132 @@ +/* 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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