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() + ); +} diff --git a/tests/ui/compiletest-self-test/test-aux-bin.rs b/tests/ui/compiletest-self-test/test-aux-bin.rs index 9e01e3ffabf..c1c28e12b3b 100644 --- a/tests/ui/compiletest-self-test/test-aux-bin.rs +++ b/tests/ui/compiletest-self-test/test-aux-bin.rs @@ -1,4 +1,4 @@ -//@ ignore-cross-compile because we run the compiled code +//@ ignore-cross-compile because aux-bin does not yet support it //@ aux-bin: print-it-works.rs //@ run-pass