about summary refs log tree commit diff
path: root/library/std/src/sys/unix/process/process_unix.rs
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2021-10-05 12:52:42 -0700
committerGitHub <noreply@github.com>2021-10-05 12:52:42 -0700
commiteb860987cf0b08153a09f2b0a03e94699e85bff7 (patch)
treeeca445c85b8e3ae3430081580eb0c214184a3ebe /library/std/src/sys/unix/process/process_unix.rs
parent960e49e89b3c09baf9197dc9c87f3ca7755a486c (diff)
parent65ef265c121c90e33dd9dd2dc3b919cf37209b71 (diff)
downloadrust-eb860987cf0b08153a09f2b0a03e94699e85bff7.tar.gz
rust-eb860987cf0b08153a09f2b0a03e94699e85bff7.zip
Rollup merge of #88828 - FabianWolff:issue-88585, r=dtolnay
Use `libc::sigaction()` instead of `sys::signal()` to prevent a deadlock

Fixes #88585. POSIX [specifies](https://man7.org/linux/man-pages/man3/fork.3p.html) that after forking,
> to avoid errors, the child process may only execute async-signal-safe operations until such time as one of the exec functions is called.

Rust's standard library does not currently adhere to this, as evidenced by #88585. The child process calls [`sys::signal()`](https://github.com/rust-lang/rust/blob/7bf0736e130e2203c58654f7353dbf9575e49d5c/library/std/src/sys/unix/android.rs#L76), which on Android calls [`libc::dlsym()`](https://github.com/rust-lang/rust/blob/7bf0736e130e2203c58654f7353dbf9575e49d5c/library/std/src/sys/unix/weak.rs#L101), which is [**not**](https://man7.org/linux/man-pages/man7/signal-safety.7.html) async-signal-safe, and in fact causes a deadlock in the example in #88585.

I think the easiest solution here would be to just call `libc::sigaction()` instead, which [is](https://man7.org/linux/man-pages/man7/signal-safety.7.html) async-signal-safe, provides the functionality we need, and is apparently available on all Android versions because it is also used e.g. [here](https://github.com/rust-lang/rust/blob/7bf0736e130e2203c58654f7353dbf9575e49d5c/library/std/src/sys/unix/stack_overflow.rs#L112-L114).
Diffstat (limited to 'library/std/src/sys/unix/process/process_unix.rs')
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs16
1 files changed, 13 insertions, 3 deletions
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 8c33051cfa4..99013efb495 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -333,9 +333,19 @@ impl Command {
             let mut set = MaybeUninit::<libc::sigset_t>::uninit();
             cvt(sigemptyset(set.as_mut_ptr()))?;
             cvt(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), ptr::null_mut()))?;
-            let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL);
-            if ret == libc::SIG_ERR {
-                return Err(io::Error::last_os_error());
+
+            #[cfg(target_os = "android")] // see issue #88585
+            {
+                let mut action: libc::sigaction = mem::zeroed();
+                action.sa_sigaction = libc::SIG_DFL;
+                cvt(libc::sigaction(libc::SIGPIPE, &action, ptr::null_mut()))?;
+            }
+            #[cfg(not(target_os = "android"))]
+            {
+                let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL);
+                if ret == libc::SIG_ERR {
+                    return Err(io::Error::last_os_error());
+                }
             }
         }