From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pl1-x629.google.com (mail-pl1-x629.google.com [IPv6:2607:f8b0:4864:20::629]) by sourceware.org (Postfix) with ESMTPS id 7A48B396ECB0 for ; Tue, 13 Jul 2021 19:33:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 7A48B396ECB0 Received: by mail-pl1-x629.google.com with SMTP id o8so2156733plg.11 for ; Tue, 13 Jul 2021 12:33:01 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=9dE1I8dfQIEqo+fwpIg+iwhn0zyLwVS8GPlQGkUfg4I=; b=pR5cGD3FzH6KswqpEYA5pO+15Tb6liTOu2poYGkvc6JeKmImjSRKJuWKo6kAV9xyCO W0sl1k3DruX+8c93KOc8zt0lSlUysu30FLz5skPHEXDCrkUOlhqdr1qIYr3cXtXg3A4k VaDxcS9hbLRJGoL3nxW1upuYN2s/WxTr0NINQclktS6/loi9lBJhZqxktKBj2vmh6kRU 33z5yMXTHQlVzcfNDlUSvB0wMqcX6qcqOqVeFxcSW3kW/cjr/Kuv520ClKua5yzfbDjB sBUD1EfjgPn5K8HuN/F58xvExTD5qzTJBFBD1D/dJ30kJ29/CykChXLHvXQ4FP2m7iYP l0AQ== X-Gm-Message-State: AOAM533vX4LAk1xOH/G8RGc/TG6v5P91fBvaX/WVJHo2tiDbELC8qfZZ aHJMzuihwfLsNuLaQhKKybiEDg== X-Google-Smtp-Source: ABdhPJxmI6708iAuRhcTsyHMeExjnWIzBvXV/o6mTQ/xCZDd4vrbWXf+qQYbG2OoR3Y0WQe5XV/aBw== X-Received: by 2002:a17:90a:3807:: with SMTP id w7mr5637905pjb.115.1626204780507; Tue, 13 Jul 2021 12:33:00 -0700 (PDT) Received: from [192.168.1.108] ([177.194.59.218]) by smtp.gmail.com with ESMTPSA id p11sm20400077pfh.196.2021.07.13.12.32.58 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 13 Jul 2021 12:33:00 -0700 (PDT) Subject: Re: [PATCH v8 3/3] Add static tests for __clone_internal To: "H.J. Lu" , libc-alpha@sourceware.org Cc: Florian Weimer , Noah Goldstein References: <20210601145516.3553627-1-hjl.tools@gmail.com> <20210601145516.3553627-4-hjl.tools@gmail.com> From: Adhemerval Zanella Message-ID: <6ec9f19a-8e6c-b5e9-859a-e72d21be9d4b@linaro.org> Date: Tue, 13 Jul 2021 16:32:56 -0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.11.0 MIME-Version: 1.0 In-Reply-To: <20210601145516.3553627-4-hjl.tools@gmail.com> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-12.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, NICE_REPLY_A, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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-List-Received-Date: Tue, 13 Jul 2021 19:33:04 -0000 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 > + . */ > + > +#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; > +} 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 > 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)); TEST_VERIFY (WIFEXITED (status)); TEST_COMPARE (WEXITSTATUS (status), 0); > + > + 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..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 > + . */ > + > +#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 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 > + . */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +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 >