|
|
ded59d |
From 436a604b7dc741fc76b5a6704c6cd8bb178518e7 Mon Sep 17 00:00:00 2001
|
|
|
ded59d |
From: Adam Yi <ayi@janestreet.com>
|
|
|
ded59d |
Date: Tue, 7 Mar 2023 07:30:02 -0500
|
|
|
ded59d |
Subject: posix: Fix system blocks SIGCHLD erroneously [BZ #30163]
|
|
|
ded59d |
|
|
|
ded59d |
Fix bug that SIGCHLD is erroneously blocked forever in the following
|
|
|
ded59d |
scenario:
|
|
|
ded59d |
|
|
|
ded59d |
1. Thread A calls system but hasn't returned yet
|
|
|
ded59d |
2. Thread B calls another system but returns
|
|
|
ded59d |
|
|
|
ded59d |
SIGCHLD would be blocked forever in thread B after its system() returns,
|
|
|
ded59d |
even after the system() in thread A returns.
|
|
|
ded59d |
|
|
|
ded59d |
Although POSIX does not require, glibc system implementation aims to be
|
|
|
ded59d |
thread and cancellation safe. This bug was introduced in
|
|
|
ded59d |
5fb7fc96350575c9adb1316833e48ca11553be49 when we moved reverting signal
|
|
|
ded59d |
mask to happen when the last concurrently running system returns,
|
|
|
ded59d |
despite that signal mask is per thread. This commit reverts this logic
|
|
|
ded59d |
and adds a test.
|
|
|
ded59d |
|
|
|
ded59d |
Signed-off-by: Adam Yi <ayi@janestreet.com>
|
|
|
ded59d |
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
|
|
ded59d |
|
|
|
ded59d |
[DJ: Edited to use integer sleep() instead of nanosleep() dependency rabbit hole]
|
|
|
ded59d |
diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c
|
|
|
ded59d |
index 634acfe264..47a0afe6bf 100644
|
|
|
ded59d |
--- a/stdlib/tst-system.c
|
|
|
ded59d |
+++ b/stdlib/tst-system.c
|
|
|
ded59d |
@@ -25,6 +25,7 @@
|
|
|
ded59d |
#include <support/check.h>
|
|
|
ded59d |
#include <support/temp_file.h>
|
|
|
ded59d |
#include <support/support.h>
|
|
|
ded59d |
+#include <support/xthread.h>
|
|
|
ded59d |
#include <support/xunistd.h>
|
|
|
ded59d |
|
|
|
ded59d |
static char *tmpdir;
|
|
|
ded59d |
@@ -71,6 +72,20 @@ call_system (void *closure)
|
|
|
ded59d |
}
|
|
|
ded59d |
}
|
|
|
ded59d |
|
|
|
ded59d |
+static void *
|
|
|
ded59d |
+sleep_and_check_sigchld (void *closure)
|
|
|
ded59d |
+{
|
|
|
ded59d |
+ double *seconds = (double *) closure;
|
|
|
ded59d |
+ char cmd[namemax];
|
|
|
ded59d |
+ sprintf (cmd, "sleep %lf" , *seconds);
|
|
|
ded59d |
+ TEST_COMPARE (system (cmd), 0);
|
|
|
ded59d |
+
|
|
|
ded59d |
+ sigset_t blocked = {0};
|
|
|
ded59d |
+ TEST_COMPARE (sigprocmask (SIG_BLOCK, NULL, &blocked), 0);
|
|
|
ded59d |
+ TEST_COMPARE (sigismember (&blocked, SIGCHLD), 0);
|
|
|
ded59d |
+ return NULL;
|
|
|
ded59d |
+}
|
|
|
ded59d |
+
|
|
|
ded59d |
static int
|
|
|
ded59d |
do_test (void)
|
|
|
ded59d |
{
|
|
|
ded59d |
@@ -154,6 +169,17 @@ do_test (void)
|
|
|
ded59d |
xchmod (_PATH_BSHELL, st.st_mode);
|
|
|
ded59d |
}
|
|
|
ded59d |
|
|
|
ded59d |
+ {
|
|
|
ded59d |
+ pthread_t long_sleep_thread = xpthread_create (NULL,
|
|
|
ded59d |
+ sleep_and_check_sigchld,
|
|
|
ded59d |
+ &(double) { 2 });
|
|
|
ded59d |
+ pthread_t short_sleep_thread = xpthread_create (NULL,
|
|
|
ded59d |
+ sleep_and_check_sigchld,
|
|
|
ded59d |
+ &(double) { 1 });
|
|
|
ded59d |
+ xpthread_join (short_sleep_thread);
|
|
|
ded59d |
+ xpthread_join (long_sleep_thread);
|
|
|
ded59d |
+ }
|
|
|
ded59d |
+
|
|
|
ded59d |
TEST_COMPARE (system (""), 0);
|
|
|
ded59d |
|
|
|
ded59d |
return 0;
|
|
|
ded59d |
diff --git a/support/shell-container.c b/support/shell-container.c
|
|
|
ded59d |
index ffa3378b5e..b1f9e793c1 100644
|
|
|
ded59d |
--- a/support/shell-container.c
|
|
|
ded59d |
+++ b/support/shell-container.c
|
|
|
ded59d |
@@ -169,6 +170,31 @@ kill_func (char **argv)
|
|
|
ded59d |
return 0;
|
|
|
ded59d |
}
|
|
|
ded59d |
|
|
|
ded59d |
+/* Emulate the "/bin/sleep" command. No suffix support. Options are
|
|
|
ded59d |
+ ignored. */
|
|
|
ded59d |
+static int
|
|
|
ded59d |
+sleep_func (char **argv)
|
|
|
ded59d |
+{
|
|
|
ded59d |
+ if (argv[0] == NULL)
|
|
|
ded59d |
+ {
|
|
|
ded59d |
+ fprintf (stderr, "sleep: missing operand\n");
|
|
|
ded59d |
+ return 1;
|
|
|
ded59d |
+ }
|
|
|
ded59d |
+ char *endptr = NULL;
|
|
|
ded59d |
+ long sec = strtol (argv[0], &endptr, 0);
|
|
|
ded59d |
+ if (endptr == argv[0] || errno == ERANGE || sec < 0)
|
|
|
ded59d |
+ {
|
|
|
ded59d |
+ fprintf (stderr, "sleep: invalid time interval '%s'\n", argv[0]);
|
|
|
ded59d |
+ return 1;
|
|
|
ded59d |
+ }
|
|
|
ded59d |
+ if (sleep (sec) < 0)
|
|
|
ded59d |
+ {
|
|
|
ded59d |
+ fprintf (stderr, "sleep: failed to nanosleep\n");
|
|
|
ded59d |
+ return 1;
|
|
|
ded59d |
+ }
|
|
|
ded59d |
+ return 0;
|
|
|
ded59d |
+}
|
|
|
ded59d |
+
|
|
|
ded59d |
/* This is a list of all the built-in commands we understand. */
|
|
|
ded59d |
static struct {
|
|
|
ded59d |
const char *name;
|
|
|
ded59d |
@@ -179,6 +206,7 @@ static struct {
|
|
|
ded59d |
{ "cp", copy_func },
|
|
|
ded59d |
{ "exit", exit_func },
|
|
|
ded59d |
{ "kill", kill_func },
|
|
|
ded59d |
+ { "sleep", sleep_func },
|
|
|
ded59d |
{ NULL, NULL }
|
|
|
ded59d |
};
|
|
|
ded59d |
|
|
|
ded59d |
diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c
|
|
|
ded59d |
index 2335a99184..d77720a625 100644
|
|
|
ded59d |
--- a/sysdeps/posix/system.c
|
|
|
ded59d |
+++ b/sysdeps/posix/system.c
|
|
|
ded59d |
@@ -179,16 +179,16 @@ do_system (const char *line)
|
|
|
ded59d |
as if the shell had terminated using _exit(127). */
|
|
|
ded59d |
status = W_EXITCODE (127, 0);
|
|
|
ded59d |
|
|
|
ded59d |
+ /* sigaction can not fail with SIGINT/SIGQUIT used with old
|
|
|
ded59d |
+ disposition. Same applies for sigprocmask. */
|
|
|
ded59d |
DO_LOCK ();
|
|
|
ded59d |
if (SUB_REF () == 0)
|
|
|
ded59d |
{
|
|
|
ded59d |
- /* sigaction can not fail with SIGINT/SIGQUIT used with old
|
|
|
ded59d |
- disposition. Same applies for sigprocmask. */
|
|
|
ded59d |
__sigaction (SIGINT, &intr, NULL);
|
|
|
ded59d |
__sigaction (SIGQUIT, &quit, NULL);
|
|
|
ded59d |
- __sigprocmask (SIG_SETMASK, &omask, NULL);
|
|
|
ded59d |
}
|
|
|
ded59d |
DO_UNLOCK ();
|
|
|
ded59d |
+ __sigprocmask (SIG_SETMASK, &omask, NULL);
|
|
|
ded59d |
|
|
|
ded59d |
if (ret != 0)
|
|
|
ded59d |
__set_errno (ret);
|