diff options
| author | Martin Nordholts <martin.nordholts@codetale.se> | 2024-04-28 18:02:21 +0200 |
|---|---|---|
| committer | Martin Nordholts <martin.nordholts@codetale.se> | 2024-05-02 19:48:29 +0200 |
| commit | cde0cde151f30e07170d0f3caa721c92bebd7afe (patch) | |
| tree | f065e316178196507ba419727c37562cdf7f828e /tests/ui/runtime | |
| parent | e27af2917b80487e9c0de00118fdcb9ccb1177f9 (diff) | |
| download | rust-cde0cde151f30e07170d0f3caa721c92bebd7afe.tar.gz rust-cde0cde151f30e07170d0f3caa721c92bebd7afe.zip | |
Change `SIGPIPE` ui from `#[unix_sigpipe = "..."]` to `-Zon-broken-pipe=...`
In the stabilization attempt of `#[unix_sigpipe = "sig_dfl"]`, a concern was raised related to using a language attribute for the feature: Long term, we want `fn lang_start()` to be definable by any crate, not just libstd. Having a special language attribute in that case becomes awkward. So as a first step towards towards the next stabilization attempt, this PR changes the `#[unix_sigpipe = "..."]` attribute to a compiler flag `-Zon-broken-pipe=...` to remove that concern, since now the language is not "contaminated" by this feature. Another point was also raised, namely that the ui should not leak **how** it does things, but rather what the **end effect** is. The new flag uses the proposed naming. This is of course something that can be iterated on further before stabilization.
Diffstat (limited to 'tests/ui/runtime')
16 files changed, 219 insertions, 0 deletions
diff --git a/tests/ui/runtime/on-broken-pipe/auxiliary/assert-inherit-sig_dfl.rs b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-inherit-sig_dfl.rs new file mode 100644 index 00000000000..b179e484524 --- /dev/null +++ b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-inherit-sig_dfl.rs @@ -0,0 +1,6 @@ +//@ aux-crate: sigpipe_utils=sigpipe-utils.rs +//@ compile-flags: -Zon-broken-pipe=inherit + +fn main() { + sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default); +} diff --git a/tests/ui/runtime/on-broken-pipe/auxiliary/assert-inherit-sig_ign.rs b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-inherit-sig_ign.rs new file mode 100644 index 00000000000..5ea435521ec --- /dev/null +++ b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-inherit-sig_ign.rs @@ -0,0 +1,6 @@ +//@ aux-crate: sigpipe_utils=sigpipe-utils.rs +//@ compile-flags: -Zon-broken-pipe=inherit + +fn main() { + sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore); +} diff --git a/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs new file mode 100644 index 00000000000..117f6134b4e --- /dev/null +++ b/tests/ui/runtime/on-broken-pipe/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/runtime/on-broken-pipe/auxiliary/sigpipe-utils.rs b/tests/ui/runtime/on-broken-pipe/auxiliary/sigpipe-utils.rs new file mode 100644 index 00000000000..3d93d50ca3f --- /dev/null +++ b/tests/ui/runtime/on-broken-pipe/auxiliary/sigpipe-utils.rs @@ -0,0 +1,33 @@ +#![feature(rustc_private)] +extern crate libc; + +/// So tests don't have to bring libc in scope themselves +pub enum SignalHandler { + Ignore, + Default, +} + +/// Helper to assert that [`libc::SIGPIPE`] has the expected signal handler. +pub fn assert_sigpipe_handler(expected_handler: SignalHandler) { + #[cfg(unix)] + #[cfg(not(any( + target_os = "emscripten", + target_os = "fuchsia", + target_os = "horizon", + target_os = "android", + )))] + { + let actual = unsafe { + let mut actual: libc::sigaction = std::mem::zeroed(); + libc::sigaction(libc::SIGPIPE, std::ptr::null(), &mut actual); + actual.sa_sigaction + }; + + let expected = match expected_handler { + SignalHandler::Ignore => libc::SIG_IGN, + SignalHandler::Default => libc::SIG_DFL, + }; + + assert_eq!(actual, expected, "actual and expected SIGPIPE disposition differs"); + } +} diff --git a/tests/ui/runtime/on-broken-pipe/child-processes.rs b/tests/ui/runtime/on-broken-pipe/child-processes.rs new file mode 100644 index 00000000000..0da2347481b --- /dev/null +++ b/tests/ui/runtime/on-broken-pipe/child-processes.rs @@ -0,0 +1,49 @@ +//@ revisions: default error kill 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 +//@ [kill] compile-flags: -Zunstable-options -Zon-broken-pipe=kill +//@ [error] compile-flags: -Zunstable-options -Zon-broken-pipe=error +//@ [inherit] compile-flags: -Zunstable-options -Zon-broken-pipe=inherit + +// Checks the signal disposition of `SIGPIPE` in child processes, and in our own +// process for robustness. + +extern crate sigpipe_utils; + +use sigpipe_utils::*; + +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"); + + // We get SIG_DFL and the child does too without any special code running + // before exec. + #[cfg(kill)] + let (we_expect, child_expects) = (SignalHandler::Default, "SIG_DFL"); + + // We get SIG_IGN and the child does too without any special code running + // before exec. + #[cfg(error)] + let (we_expect, child_expects) = (SignalHandler::Ignore, "SIG_IGN"); + + // 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/runtime/on-broken-pipe/default.rs b/tests/ui/runtime/on-broken-pipe/default.rs new file mode 100644 index 00000000000..c10d1cfacc0 --- /dev/null +++ b/tests/ui/runtime/on-broken-pipe/default.rs @@ -0,0 +1,4 @@ +//@ compile-flags: -Zon-broken-pipe=default +//@ check-fail + +fn main() {} diff --git a/tests/ui/runtime/on-broken-pipe/default.stderr b/tests/ui/runtime/on-broken-pipe/default.stderr new file mode 100644 index 00000000000..b90d7566cbb --- /dev/null +++ b/tests/ui/runtime/on-broken-pipe/default.stderr @@ -0,0 +1,2 @@ +error: incorrect value `default` for unstable option `on-broken-pipe` - either `kill`, `error`, or `inherit` was expected + diff --git a/tests/ui/runtime/on-broken-pipe/error.rs b/tests/ui/runtime/on-broken-pipe/error.rs new file mode 100644 index 00000000000..ab2036c2f41 --- /dev/null +++ b/tests/ui/runtime/on-broken-pipe/error.rs @@ -0,0 +1,10 @@ +//@ run-pass +//@ aux-build:sigpipe-utils.rs +//@ compile-flags: -Zon-broken-pipe=error + +fn main() { + extern crate sigpipe_utils; + + // `-Zon-broken-pipe=error` is active, so we expect SIGPIPE to be ignored. + sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore); +} diff --git a/tests/ui/runtime/on-broken-pipe/inherit.rs b/tests/ui/runtime/on-broken-pipe/inherit.rs new file mode 100644 index 00000000000..64909b73528 --- /dev/null +++ b/tests/ui/runtime/on-broken-pipe/inherit.rs @@ -0,0 +1,29 @@ +//@ ignore-cross-compile because aux-bin does not yet support it +//@ only-unix because SIGPIPE is a unix thing +//@ aux-bin: assert-inherit-sig_dfl.rs +//@ aux-bin: assert-inherit-sig_ign.rs +//@ run-pass +//@ compile-flags: -Zon-broken-pipe=kill + +#![feature(rustc_private)] + +extern crate libc; + +// By default the Rust runtime resets SIGPIPE to SIG_DFL before exec'ing child +// processes so opt-out of that with `-Zon-broken-pipe=kill`. See +// https://github.com/rust-lang/rust/blob/bf4de3a874753bbee3323081c8b0c133444fed2d/library/std/src/sys/pal/unix/process/process_unix.rs#L359-L384 +fn main() { + // First expect SIG_DFL in a child process with -`Zon-broken-pipe=inherit`. + assert_inherit_sigpipe_disposition("auxiliary/bin/assert-inherit-sig_dfl"); + + // With SIG_IGN we expect `-Zon-broken-pipe=inherit` to also get SIG_IGN. + unsafe { + libc::signal(libc::SIGPIPE, libc::SIG_IGN); + } + assert_inherit_sigpipe_disposition("auxiliary/bin/assert-inherit-sig_ign"); +} + +fn assert_inherit_sigpipe_disposition(aux_bin: &str) { + let mut cmd = std::process::Command::new(aux_bin); + assert!(cmd.status().unwrap().success()); +} diff --git a/tests/ui/runtime/on-broken-pipe/kill.rs b/tests/ui/runtime/on-broken-pipe/kill.rs new file mode 100644 index 00000000000..5dace6f1c6f --- /dev/null +++ b/tests/ui/runtime/on-broken-pipe/kill.rs @@ -0,0 +1,11 @@ +//@ run-pass +//@ aux-build:sigpipe-utils.rs +//@ compile-flags: -Zon-broken-pipe=kill + +fn main() { + extern crate sigpipe_utils; + + // `-Zon-broken-pipe=kill` is active, so SIGPIPE shall NOT be ignored, instead + // the default handler shall be installed + sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default); +} diff --git a/tests/ui/runtime/on-broken-pipe/no-flag-arg.rs b/tests/ui/runtime/on-broken-pipe/no-flag-arg.rs new file mode 100644 index 00000000000..2273291bfa7 --- /dev/null +++ b/tests/ui/runtime/on-broken-pipe/no-flag-arg.rs @@ -0,0 +1,4 @@ +//@ compile-flags: -Zon-broken-pipe +//@ check-fail + +fn main() {} diff --git a/tests/ui/runtime/on-broken-pipe/no-flag-arg.stderr b/tests/ui/runtime/on-broken-pipe/no-flag-arg.stderr new file mode 100644 index 00000000000..3d3e12d303c --- /dev/null +++ b/tests/ui/runtime/on-broken-pipe/no-flag-arg.stderr @@ -0,0 +1,2 @@ +error: unstable option `on-broken-pipe` requires either `kill`, `error`, or `inherit` (Z on-broken-pipe=<value>) + diff --git a/tests/ui/runtime/on-broken-pipe/not-used.rs b/tests/ui/runtime/on-broken-pipe/not-used.rs new file mode 100644 index 00000000000..e31236f2b3d --- /dev/null +++ b/tests/ui/runtime/on-broken-pipe/not-used.rs @@ -0,0 +1,9 @@ +//@ run-pass +//@ aux-build:sigpipe-utils.rs + +fn main() { + extern crate sigpipe_utils; + + // SIGPIPE shall be ignored since `-Zon-broken-pipe` is not used + sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore); +} diff --git a/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs b/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs new file mode 100644 index 00000000000..c1731200038 --- /dev/null +++ b/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs @@ -0,0 +1,14 @@ +//@ run-pass +//@ aux-build:sigpipe-utils.rs +//@ compile-flags: -Zon-broken-pipe=kill + +#![feature(rustc_attrs)] + +#[rustc_main] +fn rustc_main() { + extern crate sigpipe_utils; + + // `-Zon-broken-pipe=kill` is active, so SIGPIPE handler shall be + // SIG_DFL. Note that we have a #[rustc_main], but it should still work. + sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default); +} diff --git a/tests/ui/runtime/on-broken-pipe/wrong-flag-arg.rs b/tests/ui/runtime/on-broken-pipe/wrong-flag-arg.rs new file mode 100644 index 00000000000..14d0ac56b5a --- /dev/null +++ b/tests/ui/runtime/on-broken-pipe/wrong-flag-arg.rs @@ -0,0 +1,4 @@ +//@ compile-flags: -Zon-broken-pipe=wrong +//@ check-fail + +fn main() {} diff --git a/tests/ui/runtime/on-broken-pipe/wrong-flag-arg.stderr b/tests/ui/runtime/on-broken-pipe/wrong-flag-arg.stderr new file mode 100644 index 00000000000..3635418c845 --- /dev/null +++ b/tests/ui/runtime/on-broken-pipe/wrong-flag-arg.stderr @@ -0,0 +1,2 @@ +error: incorrect value `wrong` for unstable option `on-broken-pipe` - either `kill`, `error`, or `inherit` was expected + |
