Support #[unix_sigpipe = "inherit|sig_dfl|sig_ign"] on fn main()
This makes it possible to instruct libstd to never touch the signal handler for `SIGPIPE`, which makes programs pipeable by default (e.g. with `./your-program | head -n 1`) without `ErrorKind::BrokenPipe` errors.
This commit is contained in:
parent
ee285eab69
commit
ddee45e1d7
46 changed files with 449 additions and 43 deletions
|
|
@ -0,0 +1,26 @@
|
|||
#![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")))]
|
||||
{
|
||||
let prev = unsafe { libc::signal(libc::SIGPIPE, libc::SIG_IGN) };
|
||||
|
||||
let expected = match expected_handler {
|
||||
SignalHandler::Ignore => libc::SIG_IGN,
|
||||
SignalHandler::Default => libc::SIG_DFL,
|
||||
};
|
||||
assert_eq!(prev, expected);
|
||||
|
||||
// Unlikely to matter, but restore the old value anyway
|
||||
unsafe { libc::signal(libc::SIGPIPE, prev); };
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#![feature(unix_sigpipe)]
|
||||
#![unix_sigpipe = "inherit"] //~ error: `unix_sigpipe` attribute cannot be used at crate level
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
error: `unix_sigpipe` attribute cannot be used at crate level
|
||||
--> $DIR/unix_sigpipe-crate.rs:2:1
|
||||
|
|
||||
LL | #![unix_sigpipe = "inherit"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: perhaps you meant to use an outer attribute
|
||||
|
|
||||
LL | #[unix_sigpipe = "inherit"]
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#![feature(unix_sigpipe)]
|
||||
|
||||
#[unix_sigpipe = "sig_ign"]
|
||||
#[unix_sigpipe = "inherit"] //~ error: multiple `unix_sigpipe` attributes
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
error: multiple `unix_sigpipe` attributes
|
||||
--> $DIR/unix_sigpipe-duplicates.rs:4:1
|
||||
|
|
||||
LL | #[unix_sigpipe = "inherit"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
||||
|
|
||||
note: attribute also specified here
|
||||
--> $DIR/unix_sigpipe-duplicates.rs:3:1
|
||||
|
|
||||
LL | #[unix_sigpipe = "sig_ign"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
13
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-error.rs
Normal file
13
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-error.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// run-pass
|
||||
// aux-build:sigpipe-utils.rs
|
||||
|
||||
#![feature(unix_sigpipe)]
|
||||
|
||||
#[unix_sigpipe = "sig_ign"]
|
||||
fn main() {
|
||||
extern crate sigpipe_utils;
|
||||
|
||||
// #[unix_sigpipe = "sig_ign"] is active, so the legacy behavior of ignoring
|
||||
// SIGPIPE shall be in effect
|
||||
sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
|
||||
}
|
||||
14
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs
Normal file
14
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// run-pass
|
||||
// aux-build:sigpipe-utils.rs
|
||||
|
||||
#![feature(unix_sigpipe)]
|
||||
|
||||
#[unix_sigpipe = "inherit"]
|
||||
fn main() {
|
||||
extern crate sigpipe_utils;
|
||||
|
||||
// #[unix_sigpipe = "inherit"] is active, so SIGPIPE shall NOT be ignored,
|
||||
// instead the default handler shall be installed. (We assume that the
|
||||
// process that runs these tests have the default handler.)
|
||||
sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
|
||||
}
|
||||
4
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-list.rs
Normal file
4
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-list.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#![feature(unix_sigpipe)]
|
||||
|
||||
#[unix_sigpipe(inherit)] //~ error: malformed `unix_sigpipe` attribute input
|
||||
fn main() {}
|
||||
15
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-list.stderr
Normal file
15
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-list.stderr
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
error: malformed `unix_sigpipe` attribute input
|
||||
--> $DIR/unix_sigpipe-list.rs:3:1
|
||||
|
|
||||
LL | #[unix_sigpipe(inherit)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: the following are the possible correct uses
|
||||
|
|
||||
LL | #[unix_sigpipe = "inherit|sig_ign|sig_dfl"]
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
LL | #[unix_sigpipe]
|
||||
| ~~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#![feature(unix_sigpipe)]
|
||||
|
||||
#[unix_sigpipe = "inherit"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
|
||||
fn f() {}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
error: `unix_sigpipe` attribute can only be used on `fn main()`
|
||||
--> $DIR/unix_sigpipe-non-main-fn.rs:3:1
|
||||
|
|
||||
LL | #[unix_sigpipe = "inherit"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#![feature(unix_sigpipe)]
|
||||
|
||||
mod m {
|
||||
#[unix_sigpipe = "inherit"] //~ error: `unix_sigpipe` attribute can only be used on root `fn main()`
|
||||
fn main() {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
error: `unix_sigpipe` attribute can only be used on root `fn main()`
|
||||
--> $DIR/unix_sigpipe-non-root-main.rs:4:5
|
||||
|
|
||||
LL | #[unix_sigpipe = "inherit"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// run-pass
|
||||
// aux-build:sigpipe-utils.rs
|
||||
|
||||
fn main() {
|
||||
extern crate sigpipe_utils;
|
||||
|
||||
// SIGPIPE shall be ignored since #[unix_sigpipe = "..."] is not used
|
||||
sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// run-pass
|
||||
// aux-build:sigpipe-utils.rs
|
||||
|
||||
#![feature(unix_sigpipe)]
|
||||
|
||||
fn main() {
|
||||
extern crate sigpipe_utils;
|
||||
|
||||
// Only #![feature(unix_sigpipe)] is enabled, not #[unix_sigpipe = "..."].
|
||||
// This shall not change any behavior, so we still expect SIGPIPE to be
|
||||
// ignored
|
||||
sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// run-pass
|
||||
// aux-build:sigpipe-utils.rs
|
||||
|
||||
#![feature(unix_sigpipe)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[unix_sigpipe = "sig_dfl"]
|
||||
#[rustc_main]
|
||||
fn rustc_main() {
|
||||
extern crate sigpipe_utils;
|
||||
|
||||
// #[unix_sigpipe = "sig_dfl"] 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);
|
||||
}
|
||||
13
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-sig_dfl.rs
Normal file
13
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-sig_dfl.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// run-pass
|
||||
// aux-build:sigpipe-utils.rs
|
||||
|
||||
#![feature(unix_sigpipe)]
|
||||
|
||||
#[unix_sigpipe = "sig_dfl"]
|
||||
fn main() {
|
||||
extern crate sigpipe_utils;
|
||||
|
||||
// #[unix_sigpipe = "sig_dfl"] is active, so SIGPIPE shall NOT be ignored, instead
|
||||
// the default handler shall be installed
|
||||
sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#![feature(start)]
|
||||
#![feature(unix_sigpipe)]
|
||||
|
||||
#[start]
|
||||
#[unix_sigpipe = "inherit"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
|
||||
fn custom_start(argc: isize, argv: *const *const u8) -> isize { 0 }
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
error: `unix_sigpipe` attribute can only be used on `fn main()`
|
||||
--> $DIR/unix_sigpipe-start.rs:5:1
|
||||
|
|
||||
LL | #[unix_sigpipe = "inherit"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#![feature(unix_sigpipe)]
|
||||
|
||||
#[unix_sigpipe = "inherit"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
|
||||
struct S;
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
error: `unix_sigpipe` attribute can only be used on `fn main()`
|
||||
--> $DIR/unix_sigpipe-struct.rs:3:1
|
||||
|
|
||||
LL | #[unix_sigpipe = "inherit"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#![feature(unix_sigpipe)]
|
||||
|
||||
#[unix_sigpipe = "wrong"] //~ error: valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
error: valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
|
||||
--> $DIR/unix_sigpipe-wrong.rs:3:1
|
||||
|
|
||||
LL | #[unix_sigpipe = "wrong"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
4
src/test/ui/attributes/unix_sigpipe/unix_sigpipe.rs
Normal file
4
src/test/ui/attributes/unix_sigpipe/unix_sigpipe.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#![feature(unix_sigpipe)]
|
||||
|
||||
#[unix_sigpipe] //~ error: valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
|
||||
fn main() {}
|
||||
8
src/test/ui/attributes/unix_sigpipe/unix_sigpipe.stderr
Normal file
8
src/test/ui/attributes/unix_sigpipe/unix_sigpipe.stderr
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
error: valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
|
||||
--> $DIR/unix_sigpipe.rs:3:1
|
||||
|
|
||||
LL | #[unix_sigpipe]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue