about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMartin Nordholts <martin.nordholts@codetale.se>2024-02-24 16:48:24 +0100
committerMartin Nordholts <martin.nordholts@codetale.se>2024-03-25 06:23:47 +0100
commit71eb763d23c0406b14237be60c651d52c64d29b6 (patch)
tree974524a034b0f0215683717cc0bce17ff8806416
parenta2a2f30415ffdcfad86cd5f9948e7cfc415164c4 (diff)
downloadrust-71eb763d23c0406b14237be60c651d52c64d29b6.tar.gz
rust-71eb763d23c0406b14237be60c651d52c64d29b6.zip
unix_sigpipe: Add test for SIGPIPE disposition in child processes
For robustness, also test the disposition in our own process even if
other tests in `tests/ui/attributes/unix_sigpipe` already covers it.
-rw-r--r--tests/ui/attributes/unix_sigpipe/auxiliary/assert-sigpipe-disposition.rs34
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-and-child-processes.rs56
2 files changed, 90 insertions, 0 deletions
diff --git a/tests/ui/attributes/unix_sigpipe/auxiliary/assert-sigpipe-disposition.rs b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-sigpipe-disposition.rs
new file mode 100644
index 00000000000..117f6134b4e
--- /dev/null
+++ b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-sigpipe-disposition.rs
@@ -0,0 +1,34 @@
+// It is UB to unwind out of `fn start()` according to
+// https://doc.rust-lang.org/beta/unstable-book/language-features/start.html so
+// panic with abort to avoid UB:
+//@ compile-flags: -Cpanic=abort
+//@ no-prefer-dynamic so panic=abort works
+
+#![feature(start, rustc_private)]
+
+extern crate libc;
+
+// Use #[start] so we don't have a runtime that messes with SIGPIPE.
+#[start]
+fn start(argc: isize, argv: *const *const u8) -> isize {
+    assert_eq!(argc, 2, "Must pass SIG_IGN or SIG_DFL as first arg");
+    let arg1 = unsafe { std::ffi::CStr::from_ptr(*argv.offset(1) as *const libc::c_char) }
+        .to_str()
+        .unwrap();
+
+    let expected = match arg1 {
+        "SIG_IGN" => libc::SIG_IGN,
+        "SIG_DFL" => libc::SIG_DFL,
+        arg => panic!("Must pass SIG_IGN or SIG_DFL as first arg. Got: {}", arg),
+    };
+
+    let actual = unsafe {
+        let mut actual: libc::sigaction = std::mem::zeroed();
+        libc::sigaction(libc::SIGPIPE, std::ptr::null(), &mut actual);
+        actual.sa_sigaction
+    };
+
+    assert_eq!(actual, expected, "actual and expected SIGPIPE disposition in child differs");
+
+    0
+}
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-and-child-processes.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-and-child-processes.rs
new file mode 100644
index 00000000000..f96bd634876
--- /dev/null
+++ b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-and-child-processes.rs
@@ -0,0 +1,56 @@
+//@ revisions: default sig_dfl sig_ign inherit
+//@ ignore-cross-compile because aux-bin does not yet support it
+//@ only-unix because SIGPIPE is a unix thing
+//@ run-pass
+//@ aux-bin:assert-sigpipe-disposition.rs
+//@ aux-crate:sigpipe_utils=sigpipe-utils.rs
+
+// Checks the signal disposition of `SIGPIPE` in child processes, and in our own
+// process for robustness. Without any `unix_sigpipe` attribute, `SIG_IGN` is
+// the default. But there is a difference in how `SIGPIPE` is treated in child
+// processes with and without the attribute. Search for
+// `unix_sigpipe_attr_specified()` in the code base to learn more.
+
+#![feature(rustc_private)]
+#![cfg_attr(any(sig_dfl, sig_ign, inherit), feature(unix_sigpipe))]
+
+extern crate libc;
+extern crate sigpipe_utils;
+
+use sigpipe_utils::*;
+
+#[cfg_attr(sig_dfl, unix_sigpipe = "sig_dfl")]
+#[cfg_attr(sig_ign, unix_sigpipe = "sig_ign")]
+#[cfg_attr(inherit, unix_sigpipe = "inherit")]
+fn main() {
+    // By default we get SIG_IGN but the child gets SIG_DFL through an explicit
+    // reset before exec:
+    // https://github.com/rust-lang/rust/blob/bf4de3a874753bbee3323081c8b0c133444fed2d/library/std/src/sys/pal/unix/process/process_unix.rs#L363-L384
+    #[cfg(default)]
+    let (we_expect, child_expects) = (SignalHandler::Ignore, "SIG_DFL");
+
+    // With #[unix_sigpipe = "sig_dfl"] we get SIG_DFL and the child does too
+    // without any special code running before exec.
+    #[cfg(sig_dfl)]
+    let (we_expect, child_expects) = (SignalHandler::Default, "SIG_DFL");
+
+    // With #[unix_sigpipe = "sig_ign"] we get SIG_IGN and the child does too
+    // without any special code running before exec.
+    #[cfg(sig_ign)]
+    let (we_expect, child_expects) = (SignalHandler::Ignore, "SIG_IGN");
+
+    // With #[unix_sigpipe = "inherit"] we get SIG_DFL and the child does too
+    // without any special code running before exec.
+    #[cfg(inherit)]
+    let (we_expect, child_expects) = (SignalHandler::Default, "SIG_DFL");
+
+    assert_sigpipe_handler(we_expect);
+
+    assert!(
+        std::process::Command::new("./auxiliary/bin/assert-sigpipe-disposition")
+            .arg(child_expects)
+            .status()
+            .unwrap()
+            .success()
+    );
+}