From: Adhemerval Zanella Netto <adhemerval.zanella@linaro.org>
To: Adam Yi <ayi@janestreet.com>, libc-alpha@sourceware.org
Cc: i@adamyi.com
Subject: Re: [PATCH v3] posix: Fix system blocks SIGCHLD erroneously [BZ #30163]
Date: Thu, 2 Mar 2023 13:42:11 -0300 [thread overview]
Message-ID: <588df669-00d8-ba15-8651-2a517d8cf922@linaro.org> (raw)
In-Reply-To: <E1pX1LH-00BhtC-02@igm-qws-u21165a.delacy.com>
On 24/02/23 12:27, Adam Yi wrote:
> Fix bug that SIGCHLD is erroneously blocked forever in the following
> scenario:
>
> 1. Thread A calls system but hasn't returned yet
> 2. Thread B calls another system but returns
>
> SIGCHLD would be blocked forever in thread B after its system() returns,
> even after the system() in thread A returns.
>
> Although POSIX does not require, glibc system implementation aims to be
> thread and cancellation safe. This bug was introduced in
> 5fb7fc96350575c9adb1316833e48ca11553be49 when we moved reverting signal
> mask to happen when the last concurrently running system returns,
> despite that signal mask is per thread. This commit reverts this logic
> and adds a test.
Thanks for working on this, just some more minor comments below.
> ---
> stdlib/tst-system.c | 28 ++++++++++++++++++++
> support/Makefile | 2 ++
> support/dtotimespec-time64.c | 27 +++++++++++++++++++
> support/dtotimespec.c | 50 ++++++++++++++++++++++++++++++++++++
> support/shell-container.c | 13 ++++++++++
> support/timespec.h | 4 +++
> sysdeps/posix/system.c | 6 ++---
> 7 files changed, 127 insertions(+), 3 deletions(-)
> create mode 100644 support/dtotimespec-time64.c
> create mode 100644 support/dtotimespec.c
>
> diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c
> index 634acfe264..736d2bf95b 100644
> --- a/stdlib/tst-system.c
> +++ b/stdlib/tst-system.c
> @@ -20,6 +20,8 @@
> #include <string.h>
> #include <signal.h>
> #include <paths.h>
> +#include <pthread.h>
> +#include <inttypes.h>
>
> #include <support/capture_subprocess.h>
> #include <support/check.h>
> @@ -71,6 +73,20 @@ call_system (void *closure)
> }
> }
>
> +static void *
> +sleep_and_check_sigchld (void *closure)
> +{
> + double *seconds = (double *) closure;
> + char cmd[namemax];
> + sprintf (cmd, "sleep %lf" , *seconds);
> + TEST_COMPARE (system (cmd), 0);
> +
> + sigset_t blocked = {0};
> + TEST_COMPARE (sigprocmask (SIG_BLOCK, NULL, &blocked), 0);
> + TEST_COMPARE (sigismember (&blocked, SIGCHLD), 0);
> + return NULL;
> +}
> +
> static int
> do_test (void)
> {
> @@ -154,6 +170,18 @@ do_test (void)
> xchmod (_PATH_BSHELL, st.st_mode);
> }
>
> + {
> + pthread_t long_sleep_thread, short_sleep_thread;
> +
> + TEST_COMPARE (pthread_create (&long_sleep_thread, NULL,
> + sleep_and_check_sigchld, &(double) { 0.2 }), 0);
> + TEST_COMPARE (pthread_create (&short_sleep_thread, NULL,
> + sleep_and_check_sigchld, &(double) { 0.1 }), 0);
> +
> + TEST_COMPARE (pthread_join (short_sleep_thread, NULL), 0);
> + TEST_COMPARE (pthread_join (long_sleep_thread, NULL), 0);
Use xpthread_create and xpthread_join here:
pthread_t short_sleep_thread = xpthread_create (NULL,
sleep_and_check_sigchld, &(double) { 0.2 });
pthread_t long_sleep_thread = xpthread_create (NULL,
sleep_and_check_sigchld, &(double) { 0.1 });
xpthread_join (short_sleep_thread);
xpthread_join (sleep_and_check_sigchld);
> + }
> +
> TEST_COMPARE (system (""), 0);
>
> return 0> diff --git a/support/Makefile b/support/Makefile
> index b29b7eb505..48cd74581d 100644
> --- a/support/Makefile
> +++ b/support/Makefile
> @@ -32,6 +32,8 @@ libsupport-routines = \
> check_hostent \
> check_netent \
> delayed_exit \
> + dtotimespec \
> + dtotimespec-time64 \
> ignore_stderr \
> next_to_fault \
> oom_error \
Ok.
> diff --git a/support/dtotimespec-time64.c b/support/dtotimespec-time64.c
> new file mode 100644
> index 0000000000..b3d5e351e3
> --- /dev/null
> +++ b/support/dtotimespec-time64.c
> @@ -0,0 +1,27 @@
> +/* Convert double to timespec. 64-bit time support.
> + Copyright (C) 2011-2023 Free Software Foundation, Inc.
> + This file is part of the GNU C Library and is also part of gnulib.
> + Patches to this file should be submitted to both projects.
> +
> + 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 <time.h>
> +
> +#if __TIMESIZE != 64
> +# define timespec __timespec64
> +# define time_t __time64_t
> +# define dtotimespec dtotimespec_time64
> +# include "dtotimespec.c"
> +#endif
Ok.
> diff --git a/support/dtotimespec.c b/support/dtotimespec.c
> new file mode 100644
> index 0000000000..860403b83c
> --- /dev/null
> +++ b/support/dtotimespec.c
> @@ -0,0 +1,50 @@
> +/* Convert double to timespec.
> + Copyright (C) 2011-2023 Free Software Foundation, Inc.
> + This file is part of the GNU C Library and is also part of gnulib.
> + Patches to this file should be submitted to both projects.
> +
> + 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/>. */
> +
> +/* Convert the double value SEC to a struct timespec. Round toward
> + positive infinity. On overflow, return an extremal value. */
> +
> +#include <support/timespec.h>
> +#include <intprops.h>
> +
> +struct timespec
> +dtotimespec (double sec)
> +{
> + if (! (TYPE_MINIMUM (time_t) < sec))
> + return make_timespec (TYPE_MINIMUM (time_t), 0);
> + else if (! (sec < 1.0 + TYPE_MAXIMUM (time_t)))
> + return make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_HZ - 1);
> + else
> + {
> + time_t s = sec;
> + double frac = TIMESPEC_HZ * (sec - s);
> + long ns = frac;
> + ns += ns < frac;
> + s += ns / TIMESPEC_HZ;
> + ns %= TIMESPEC_HZ;
> +
> + if (ns < 0)
> + {
> + s--;
> + ns += TIMESPEC_HZ;
> + }
> +
> + return make_timespec (s, ns);
> + }
> +}
Ok.
> diff --git a/support/shell-container.c b/support/shell-container.c
> index e9ac9b6d04..a2be314ad9 100644
> --- a/support/shell-container.c
> +++ b/support/shell-container.c
> @@ -39,6 +39,7 @@
> #include <error.h>
>
> #include <support/support.h>
> +#include <support/timespec.h>
>
> /* Design considerations
>
> @@ -171,6 +172,17 @@ kill_func (char **argv)
> return 0;
> }
>
> +/* Emulate the "/bin/sleep" command. No suffix support. Options are
> + ignored. */
> +static int
> +sleep_func (char **argv)
> +{
> + double sec = atof (argv[0]);
Add some parsing check here:
TEST_VERIFY_EXIT (argv[0] != NULL);
char *endptr = NULL;
double sec = strtod (argv[0], &endptr);
TEST_VERIFY_EXIT (endptr != argv[0] && errno != ERANGE);
/* No suffix support and only positive values. */
TEST_VERIFY_EXIT (sec >= 0.0);
> + struct timespec ts = dtotimespec (sec);
> + nanosleep (&ts, NULL);
> + return 0;
> +}
> +
> /* This is a list of all the built-in commands we understand. */
> static struct {
> const char *name;
> @@ -181,6 +193,7 @@ static struct {
> { "cp", copy_func },
> { "exit", exit_func },
> { "kill", kill_func },
> + { "sleep", sleep_func },
> { NULL, NULL }
> };
>
> diff --git a/support/timespec.h b/support/timespec.h
> index 77b1e4e8d6..9559836d4c 100644
> --- a/support/timespec.h
> +++ b/support/timespec.h
> @@ -57,6 +57,8 @@ int support_timespec_check_in_range (struct timespec expected,
> struct timespec observed,
> double lower_bound, double upper_bound);
>
> +struct timespec dtotimespec (double sec) __attribute__((const));
> +
> #else
> struct timespec __REDIRECT (timespec_add, (struct timespec, struct timespec),
> timespec_add_time64);
> @@ -82,6 +84,8 @@ int __REDIRECT (support_timespec_check_in_range, (struct timespec expected,
> double lower_bound,
> double upper_bound),
> support_timespec_check_in_range_time64);
> +
> +struct timespec __REDIRECT (dtotimespec, (double sec), dtotimespec_time64);
> #endif
>
> /* Check that the timespec on the left represents a time before the
> diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c
> index 2335a99184..d77720a625 100644
> --- a/sysdeps/posix/system.c
> +++ b/sysdeps/posix/system.c
> @@ -179,16 +179,16 @@ do_system (const char *line)
> as if the shell had terminated using _exit(127). */
> status = W_EXITCODE (127, 0);
>
> + /* sigaction can not fail with SIGINT/SIGQUIT used with old
> + disposition. Same applies for sigprocmask. */
> DO_LOCK ();
> if (SUB_REF () == 0)
> {
> - /* sigaction can not fail with SIGINT/SIGQUIT used with old
> - disposition. Same applies for sigprocmask. */
> __sigaction (SIGINT, &intr, NULL);
> __sigaction (SIGQUIT, &quit, NULL);
> - __sigprocmask (SIG_SETMASK, &omask, NULL);
> }
> DO_UNLOCK ();
> + __sigprocmask (SIG_SETMASK, &omask, NULL);
>
> if (ret != 0)
> __set_errno (ret);
next prev parent reply other threads:[~2023-03-02 16:42 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-02-24 17:31 [PATCH] " Adam Yi
2023-02-24 15:27 ` [PATCH v3] " Adam Yi
2023-03-02 16:42 ` Adhemerval Zanella Netto [this message]
2023-03-03 5:11 ` Adam Yi
2023-03-03 12:00 ` Adhemerval Zanella Netto
2023-03-06 4:27 ` [PATCH v4] " Adam Yi
2023-03-06 9:04 ` Andreas Schwab
2023-03-07 1:52 ` [PATCH v5] " Adam Yi
2023-03-07 12:18 ` Adhemerval Zanella Netto
2023-03-07 12:33 ` Florian Weimer
2023-03-07 12:33 ` Adam Yi
2023-03-07 12:30 ` [PATCH v6] " Adam Yi
2023-03-07 12:55 ` Adhemerval Zanella Netto
2023-03-07 22:50 ` Joseph Myers
2023-03-08 8:17 ` Adam Yi
2023-02-24 18:00 ` [PATCH] " Adam Yi
2023-02-24 20:18 ` Adhemerval Zanella Netto
2023-03-01 2:36 ` Adam Yi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=588df669-00d8-ba15-8651-2a517d8cf922@linaro.org \
--to=adhemerval.zanella@linaro.org \
--cc=ayi@janestreet.com \
--cc=i@adamyi.com \
--cc=libc-alpha@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).