Auto merge of #97802 - Enselic:add-no_ignore_sigkill-feature, r=joshtriplett
Support `#[unix_sigpipe = "inherit|sig_dfl"]` on `fn main()` to prevent ignoring `SIGPIPE`
When enabled, programs don't have to explicitly handle `ErrorKind::BrokenPipe` any longer. Currently, the program
```rust
fn main() { loop { println!("hello world"); } }
```
will print an error if used with a short-lived pipe, e.g.
% ./main | head -n 1
hello world
thread 'main' panicked at 'failed printing to stdout: Broken pipe (os error 32)', library/std/src/io/stdio.rs:1016:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
by enabling `#[unix_sigpipe = "sig_dfl"]` like this
```rust
#![feature(unix_sigpipe)]
#[unix_sigpipe = "sig_dfl"]
fn main() { loop { println!("hello world"); } }
```
there is no error, because `SIGPIPE` will not be ignored and thus the program will be killed appropriately:
% ./main | head -n 1
hello world
The current libstd behaviour of ignoring `SIGPIPE` before `fn main()` can be explicitly requested by using `#[unix_sigpipe = "sig_ign"]`.
With `#[unix_sigpipe = "inherit"]`, no change at all is made to `SIGPIPE`, which typically means the behaviour will be the same as `#[unix_sigpipe = "sig_dfl"]`.
See https://github.com/rust-lang/rust/issues/62569 and referenced issues for discussions regarding the `SIGPIPE` problem itself
See the [this](https://rust-lang.zulipchat.com/#narrow/stream/219381-t-libs/topic/Proposal.3A.20First.20step.20towards.20solving.20the.20SIGPIPE.20problem) Zulip topic for more discussions, including about this PR.
Tracking issue: https://github.com/rust-lang/rust/issues/97889
This commit is contained in:
@@ -98,7 +98,7 @@ pub extern "C" fn __rust_abort() {
|
||||
|
||||
// SAFETY: must be called only once during runtime initialization.
|
||||
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
|
||||
pub unsafe fn init(argc: isize, argv: *const *const u8) {
|
||||
pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
|
||||
let _ = net::init();
|
||||
args::init(argc, argv);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ pub mod locks {
|
||||
|
||||
// SAFETY: must be called only once during runtime initialization.
|
||||
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
|
||||
pub unsafe fn init(argc: isize, argv: *const *const u8) {
|
||||
pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
|
||||
unsafe {
|
||||
args::init(argc, argv);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ pub mod locks {
|
||||
|
||||
// SAFETY: must be called only once during runtime initialization.
|
||||
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
|
||||
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
|
||||
pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
|
||||
|
||||
// SAFETY: must be called only once during runtime cleanup.
|
||||
pub unsafe fn cleanup() {}
|
||||
|
||||
@@ -44,12 +44,13 @@ pub mod thread_parker;
|
||||
pub mod time;
|
||||
|
||||
#[cfg(target_os = "espidf")]
|
||||
pub fn init(argc: isize, argv: *const *const u8) {}
|
||||
pub fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {}
|
||||
|
||||
#[cfg(not(target_os = "espidf"))]
|
||||
// SAFETY: must be called only once during runtime initialization.
|
||||
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
|
||||
pub unsafe fn init(argc: isize, argv: *const *const u8) {
|
||||
// See `fn init()` in `library/std/src/rt.rs` for docs on `sigpipe`.
|
||||
pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
|
||||
// The standard streams might be closed on application startup. To prevent
|
||||
// std::io::{stdin, stdout,stderr} objects from using other unrelated file
|
||||
// resources opened later, we reopen standards streams when they are closed.
|
||||
@@ -61,8 +62,9 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
|
||||
// want!
|
||||
//
|
||||
// Hence, we set SIGPIPE to ignore when the program starts up in order
|
||||
// to prevent this problem.
|
||||
reset_sigpipe();
|
||||
// to prevent this problem. Add `#[unix_sigpipe = "..."]` above `fn main()` to
|
||||
// alter this behavior.
|
||||
reset_sigpipe(sigpipe);
|
||||
|
||||
stack_overflow::init();
|
||||
args::init(argc, argv);
|
||||
@@ -151,9 +153,31 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn reset_sigpipe() {
|
||||
unsafe fn reset_sigpipe(#[allow(unused_variables)] sigpipe: u8) {
|
||||
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "horizon")))]
|
||||
rtassert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
|
||||
{
|
||||
// We don't want to add this as a public type to libstd, nor do we
|
||||
// want to `include!` a file from the compiler (which would break
|
||||
// Miri and xargo for example), so we choose to duplicate these
|
||||
// constants from `compiler/rustc_session/src/config/sigpipe.rs`.
|
||||
// See the other file for docs. NOTE: Make sure to keep them in
|
||||
// sync!
|
||||
mod sigpipe {
|
||||
pub const INHERIT: u8 = 1;
|
||||
pub const SIG_IGN: u8 = 2;
|
||||
pub const SIG_DFL: u8 = 3;
|
||||
}
|
||||
|
||||
let handler = match sigpipe {
|
||||
sigpipe::INHERIT => None,
|
||||
sigpipe::SIG_IGN => Some(libc::SIG_IGN),
|
||||
sigpipe::SIG_DFL => Some(libc::SIG_DFL),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
if let Some(handler) = handler {
|
||||
rtassert!(signal(libc::SIGPIPE, handler) != libc::SIG_ERR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ pub mod memchr {
|
||||
|
||||
// SAFETY: must be called only once during runtime initialization.
|
||||
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
|
||||
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
|
||||
pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
|
||||
|
||||
// SAFETY: must be called only once during runtime cleanup.
|
||||
// NOTE: this is not guaranteed to run, for example when the program aborts.
|
||||
|
||||
@@ -48,7 +48,7 @@ cfg_if::cfg_if! {
|
||||
|
||||
// SAFETY: must be called only once during runtime initialization.
|
||||
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
|
||||
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
|
||||
pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {
|
||||
stack_overflow::init();
|
||||
|
||||
// Normally, `thread::spawn` will call `Thread::set_name` but since this thread already
|
||||
|
||||
Reference in New Issue
Block a user