-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prevent broken pipes causing ICEs #49606
Conversation
Maybe we should just use that crate? I guess this is minimal enough code it's probably not worth adding an external dependency. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like I'd rather not entable libcore/libstd if we can avoid it. Thoughts?
src/libstd/io/stdio.rs
Outdated
#[doc(hidden)] | ||
pub fn _try_print(args: fmt::Arguments) -> io::Result<()> { | ||
try_print_to(args, &LOCAL_STDOUT, stdout) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems fine, but I feel like we could easily use stable APIs to build this, no? Like, can't we just make librustc_driver
use write!
or something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The primary reason I did it this way was to make sure try_println!
had ensured identical behaviour as println!
(apart from the panic behaviour). I'm not sure how important this is in practice, but felt that it was generally a good idea to keep things familiar, so as not to introduce some inconsistency that would lead to a different issue in the future. (Plus, if we ever want to make such functionality public, it's trivial.)
If you think this is overcomplicating things, though, I could write
inside librustc_driver
instead, yeah.
Yes, it really is very minimal. Additionally, the behaviour of the crate isn't exactly the same as |
What's an example of how |
My main concern was: Line 701 in 7678d50
write! wouldn't have this stdout fallback, though I'm not sure if this would ever actually be an issue from the context of librustc_driver . I'm not really familiar with the context.
|
OK, well, I don't really care that much either way. r=me for the compiler bits, but I'd like somebody from @rust-lang/libs to at least glance over the changes to |
I'm personally a little concerned about the long-term maintainability of a solution like this, for example this doesn't change anything in |
@alexcrichton: why/where was the signal handler originally disabled? |
rust/src/libstd/sys/unix/mod.rs Line 71 in f1ea23e
It's disabled by default because it only really makes sense for CLI programs that only touch stdin/stdout/stderr and don't do any e.g. networking. |
@sfackler: Thanks! I didn't realise that EPIPE triggered SIGPIPE.
Also, are we happy with just exiting, or do we want to trigger an message? |
Now an EPIPE will simply terminate rustc/rustdoc, by (re-)overriding the SIGPIPE signal handler. |
src/rustc/rustc.rs
Outdated
unsafe { | ||
// Set the SIGPIPE signal handler, so that an EPIPE | ||
// will cause rustc to terminate, as expected. | ||
assert!(signal(libc::SIGPIPE, libc::SIG_DFL) != libc::SIG_ERR); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this may not compile on Windows, and could the logic between rustc and rustdoc be shared?
Ping from triage @alexcrichton! The author addressed your comments! |
📌 Commit 7ab31f6 has been approved by |
Prevent broken pipes causing ICEs As the private `std::io::print_to` panics if there is an I/O error, which is used by `println!`, the compiler would ICE if one attempted to use a broken pipe (e.g. `rustc --help | false`). This introduces a new (private) macro `try_println!` which allows us to avoid this. As a side note, it seems this macro might be useful publicly (and actually there seems to be [a crate specifically for this purpose](https://crates.io/crates/try_print/)), though that can probably be left for a future discussion. One slight alternative approach would be to simply early exit without an error (i.e. exit code `0`), which [this comment](rust-lang#34376 (comment)) suggests is the usual approach. I've opted not to take that approach initially, because I think it's more helpful to know when there is a broken pipe. Fixes rust-lang#34376.
Rollup of 8 pull requests Successful merges: - #49555 (Inline most of the code paths for conversions with boxed slices) - #49606 (Prevent broken pipes causing ICEs) - #49646 (Use box syntax instead of Box::new in Mutex::remutex on Windows) - #49647 (Remove `underscore_lifetimes` and `match_default_bindings` from active feature list) - #49931 (Fix incorrect span in `&mut` suggestion) - #49959 (rustbuild: allow building tools with debuginfo) - #49965 (Remove warning about f64->f32 cast being potential UB) - #49994 (Remove unnecessary indentation in rustdoc book codeblock.) Failed merges:
…h726 rustc: Use `unix_sigpipe` instead of `rustc_driver::set_sigpipe_handler` This is the first (known) step towards starting to use `unix_sigpipe` in the wild. Eventually, `rustc_driver::set_sigpipe_handler` can be removed and all clients can use `unix_sigpipe` instead. For now we just start using `unix_sigpipe` in one place: `rustc` itself. It is easy to manually verify this change. If you remove `#[unix_sigpipe = "sig_dfl"]` and run `./x.py build` you will get an ICE when you do `./build/x86_64-unknown-linux-gnu/stage1/bin/rustc --help | false`. Add back `#[unix_sigpipe = "sig_dfl"]` and the ICE disappears again. PR that added `set_sigpipe_handler`: rust-lang#49606 Tracking issue for `unix_sigpipe`: rust-lang#97889 Not sure exactly how to label this PR. Going with T-libs for now since this is a T-libs feature. `@rustdoc` labels +T-libs
…triddle rustdoc: Use `unix_sigpipe` instead of `rustc_driver::set_sigpipe_handler` Do what was already done for `rustc` in rust-lang#102587, namely start using `unix_sigpipe` instead of `rustc_driver::set_sigpipe_handler`. After this has been merged, we can completely remove `rustc_driver::set_sigpipe_handler`. PR that added `set_sigpipe_handler`: rust-lang#49606 Tracking issue for `unix_sigpipe`: rust-lang#97889 Verification of this change --------------------------- 1. Remove `#[unix_sigpipe = "sig_dfl"]` 1. Run `./x.py build` 1. Run `./build/aarch64-apple-darwin/stage1/bin/rustdoc --help | false` 1. Observe ICE 1. Add back `#[unix_sigpipe = "sig_dfl"]` 1. Run `./x.py build` 1. Run `./build/aarch64-apple-darwin/stage1/bin/rustdoc --help | false` 1. Observe ICE fixed `@rustbot` labels +T-rustdoc
…triddle rustdoc: Use `unix_sigpipe` instead of `rustc_driver::set_sigpipe_handler` Do what was already done for `rustc` in rust-lang#102587, namely start using `unix_sigpipe` instead of `rustc_driver::set_sigpipe_handler`. After this has been merged, we can completely remove `rustc_driver::set_sigpipe_handler`. PR that added `set_sigpipe_handler`: rust-lang#49606 Tracking issue for `unix_sigpipe`: rust-lang#97889 Verification of this change --------------------------- 1. Remove `#[unix_sigpipe = "sig_dfl"]` 1. Run `./x.py build` 1. Run `./build/aarch64-apple-darwin/stage1/bin/rustdoc --help | false` 1. Observe ICE 1. Add back `#[unix_sigpipe = "sig_dfl"]` 1. Run `./x.py build` 1. Run `./build/aarch64-apple-darwin/stage1/bin/rustdoc --help | false` 1. Observe ICE fixed ``@rustbot`` labels +T-rustdoc
…h726 rustc: Use `unix_sigpipe` instead of `rustc_driver::set_sigpipe_handler` This is the first (known) step towards starting to use `unix_sigpipe` in the wild. Eventually, `rustc_driver::set_sigpipe_handler` can be removed and all clients can use `unix_sigpipe` instead. For now we just start using `unix_sigpipe` in one place: `rustc` itself. It is easy to manually verify this change. If you remove `#[unix_sigpipe = "sig_dfl"]` and run `./x.py build` you will get an ICE when you do `./build/x86_64-unknown-linux-gnu/stage1/bin/rustc --help | false`. Add back `#[unix_sigpipe = "sig_dfl"]` and the ICE disappears again. PR that added `set_sigpipe_handler`: rust-lang#49606 Tracking issue for `unix_sigpipe`: rust-lang#97889 Not sure exactly how to label this PR. Going with T-libs for now since this is a T-libs feature. ``@rustdoc`` labels +T-libs
…h726 rustc: Use `unix_sigpipe` instead of `rustc_driver::set_sigpipe_handler` This is the first (known) step towards starting to use `unix_sigpipe` in the wild. Eventually, `rustc_driver::set_sigpipe_handler` can be removed and all clients can use `unix_sigpipe` instead. For now we just start using `unix_sigpipe` in one place: `rustc` itself. It is easy to manually verify this change. If you remove `#[unix_sigpipe = "sig_dfl"]` and run `./x.py build` you will get an ICE when you do `./build/x86_64-unknown-linux-gnu/stage1/bin/rustc --help | false`. Add back `#[unix_sigpipe = "sig_dfl"]` and the ICE disappears again. PR that added `set_sigpipe_handler`: rust-lang#49606 Tracking issue for `unix_sigpipe`: rust-lang#97889 Not sure exactly how to label this PR. Going with T-libs for now since this is a T-libs feature. ```@rustdoc``` labels +T-libs
…h726 rustc: Use `unix_sigpipe` instead of `rustc_driver::set_sigpipe_handler` This is the first (known) step towards starting to use `unix_sigpipe` in the wild. Eventually, `rustc_driver::set_sigpipe_handler` can be removed and all clients can use `unix_sigpipe` instead. For now we just start using `unix_sigpipe` in one place: `rustc` itself. It is easy to manually verify this change. If you remove `#[unix_sigpipe = "sig_dfl"]` and run `./x.py build` you will get an ICE when you do `./build/x86_64-unknown-linux-gnu/stage1/bin/rustc --help | false`. Add back `#[unix_sigpipe = "sig_dfl"]` and the ICE disappears again. PR that added `set_sigpipe_handler`: rust-lang#49606 Tracking issue for `unix_sigpipe`: rust-lang#97889 Not sure exactly how to label this PR. Going with T-libs for now since this is a T-libs feature. ````@rustdoc```` labels +T-libs
rustc: Use `unix_sigpipe` instead of `rustc_driver::set_sigpipe_handler` This is the first (known) step towards starting to use `unix_sigpipe` in the wild. Eventually, `rustc_driver::set_sigpipe_handler` can be removed and all clients can use `unix_sigpipe` instead. For now we just start using `unix_sigpipe` in one place: `rustc` itself. It is easy to manually verify this change. If you remove `#[unix_sigpipe = "sig_dfl"]` and run `./x.py build` you will get an ICE when you do `./build/x86_64-unknown-linux-gnu/stage1/bin/rustc --help | false`. Add back `#[unix_sigpipe = "sig_dfl"]` and the ICE disappears again. PR that added `set_sigpipe_handler`: rust-lang/rust#49606 Tracking issue for `unix_sigpipe`: #97889 Not sure exactly how to label this PR. Going with T-libs for now since this is a T-libs feature. ````@rustdoc```` labels +T-libs
…, r=tmiasko Remove `rustc_driver::set_sigpipe_handler()` Its usage was removed in rust-lang#102587 and rust-lang#103495, so we do not need to keep it around any longer. According to [preliminary input](https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/Find.20.60rustc_driver.60.20dependent.20projects.3F/near/304490764), we do not need to worry about any deprecation cycle for this explicitly unstable API, and can just straight up remove it. PR that added `set_sigpipe_handler`: rust-lang#49606 Tracking issue for `unix_sigpipe`: rust-lang#97889 Migration instructions for any remaining clients --- Change from ```rust #![feature(rustc_private)] extern crate rustc_driver; fn main() { rustc_driver::set_sigpipe_handler(); // ... ``` to ```rust #![feature(unix_sigpipe)] #[unix_sigpipe = "sig_dfl"] fn main() { // ... ``` `@rustbot` labels +T-compiler
…, r=tmiasko Remove `rustc_driver::set_sigpipe_handler()` Its usage was removed in rust-lang#102587 and rust-lang#103495, so we do not need to keep it around any longer. According to [preliminary input](https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/Find.20.60rustc_driver.60.20dependent.20projects.3F/near/304490764), we do not need to worry about any deprecation cycle for this explicitly unstable API, and can just straight up remove it. PR that added `set_sigpipe_handler`: rust-lang#49606 Tracking issue for `unix_sigpipe`: rust-lang#97889 Migration instructions for any remaining clients --- Change from ```rust #![feature(rustc_private)] extern crate rustc_driver; fn main() { rustc_driver::set_sigpipe_handler(); // ... ``` to ```rust #![feature(unix_sigpipe)] #[unix_sigpipe = "sig_dfl"] fn main() { // ... ``` ``@rustbot`` labels +T-compiler
…r-ozkan Revert rust-lang#131060 "Drop conditionally applied cargo `-Zon-broken-pipe=kill` flags" In [rust-lang#131059] we found out that `-Zon-broken-pipe=kill` is actually **load-bearing**[^1] for (at least) `rustc` and `rustdoc` to have the kill-process-on-broken-pipe behavior, e.g. `rustc --print=sysroot | false` will ICE and `rustdoc --print=sysroot | false` will panic on a broken pipe. This PR reverts 5a7058c (reverts PR rust-lang#131060) in favor of a future fix to *unconditionally* apply `-Zon-broken-pipe=kill` to tool builds and also not drop the `-Zon-broken-pipe=kill` flag for rustc binary builds. I could not figure out how to write a regression test for the `rustc --print=sysroot | false` behavior on Unix, so this is a plain revert for now. This revert will unfortunately reintroduce rust-lang#130980 until we fix it again with the different approach. See more details at <rust-lang#131059 (comment)> and in the timeline below. ### Timeline of kill-process-on-broken-pipe behavior changes See [`unix_sigpipe` tracking issue rust-lang#97889][rust-lang#97889] for more context around unix sigpipe handling. - From the very beginning since 2014, Rust binaries by default use `sig_ign`. This meant that if output pipe is broken yet the program tries to use `println!` and such, there will be a broken pipe panic from std. This lead to ICEs from e.g. `rustc --help | false` [rust-lang#34376]. - [rust-lang#49606] mitigated [rust-lang#34376] by adding an explicit signal handler to `rustc_driver` register a sigpipe handler with `SIG_DFL` which will cause the binary using `rustc_driver` to terminate if `rustc_driver::set_sigpipe_handler()` is called. `rustc`'s main binary wrapper uses `rustc_driver::set_sigpipe_handler()`, and so does `rustdoc`. - A more universal way to set sigpipe behavior for Unix was introduced as part of [rust-lang#97889], i.e. `# [unix_sigpipe = "sig_dfl"]` attribute. - [rust-lang#102587] migrated `rustc` to use `#[unix_sigpipe = "sig_dfl"]` instead of `rustc_driver::set_sigpipe_handler`. - [rust-lang#103495] migrated `rustdoc` to use `#[unix_sigpipe = "sig_dfl"]` instead of `rustc_driver::set_sigpipe_handler`. `rustc_driver::set_sigpipe_handler` was removed. - Following concerns about sigpipe setting UI in [rust-lang#97889], the UI for specifying sigpipe behavior was changed in [rust-lang#124480] from `#[unix_sigpipe = "sig_dfl"]` attribute to the commmand line flag `-Zon-broken-pipe=kill`. - In the same PR, `#[unix_sigpipe = "sig_dfl"]` were removed from `rustc` and `rustdoc` main binary crate entry points in favor of the command line flag. Kill-process-on-broken-pipe behavior was preserved by adding `-Zon-broken-pipe=kill` for `rustdoc` tool build step and `rustc` during compile steps. - [rust-lang#126934] added `-Zon-broken-pipe=kill` for tool builds *except* for cargo to help with some miri tests because at the time the PR was written, this would lead to a couple of cargo test failures. Conditionally setting `RUSTFLAGS` can lead to tool build invalidation, e.g. building `cargo` without `-Zon-broken-pipe=kill` but `clippy` with the flag can lead to invalidation of the tool build cache. This is not a problem at the time, because nothing (not even miri) tests built stage 1 cargo (all used initial cargo). - In [rust-lang#130634] we found out that `run-make` tests like `compiler-builtins` needed stage 1 cargo, not just beta bootstrap cargo, because there can be changes that are present in stage 1 cargo but absent in beta cargo, which was blocking a beta backport. - [rust-lang#130642] and later [rust-lang#130739] now build stage 1 cargo. And as previously mentioned, since `-Zon-broken-pipe=kill` was specifically *not* set for cargo, this caused tool build cache invalidation meaning rebuilds of stage 1 even if nothing in source was changed due to differing `RUSTFLAGS` since `run-make` also builds `rustdoc` and such [rust-lang#130980]. [rust-lang#34376]: rust-lang#34376 [rust-lang#49606]: rust-lang#49606 [rust-lang#97889]: rust-lang#97889 [rust-lang#102587]: rust-lang#102587 [rust-lang#103495]: rust-lang#103495 [rust-lang#124480]: rust-lang#124480 [rust-lang#130634]: rust-lang#130634 [rust-lang#130642]: rust-lang#130642 [rust-lang#130739]: rust-lang#130739 [rust-lang#130980]: rust-lang#130980 [rust-lang#131059]: rust-lang#131059 [^1]: rust-lang#131059 (comment) r? `@onur-ozkan` (or bootstrap)
…r-ozkan Revert rust-lang#131060 "Drop conditionally applied cargo `-Zon-broken-pipe=kill` flags" In [rust-lang#131059] we found out that `-Zon-broken-pipe=kill` is actually **load-bearing**[^1] for (at least) `rustc` and `rustdoc` to have the kill-process-on-broken-pipe behavior, e.g. `rustc --print=sysroot | false` will ICE and `rustdoc --print=sysroot | false` will panic on a broken pipe. This PR reverts 5a7058c (reverts PR rust-lang#131060) in favor of a future fix to *unconditionally* apply `-Zon-broken-pipe=kill` to tool builds and also not drop the `-Zon-broken-pipe=kill` flag for rustc binary builds. I could not figure out how to write a regression test for the `rustc --print=sysroot | false` behavior on Unix, so this is a plain revert for now. This revert will unfortunately reintroduce rust-lang#130980 until we fix it again with the different approach. See more details at <rust-lang#131059 (comment)> and in the timeline below. ### Timeline of kill-process-on-broken-pipe behavior changes See [`unix_sigpipe` tracking issue rust-lang#97889][rust-lang#97889] for more context around unix sigpipe handling. - From the very beginning since 2014, Rust binaries by default use `sig_ign`. This meant that if output pipe is broken yet the program tries to use `println!` and such, there will be a broken pipe panic from std. This lead to ICEs from e.g. `rustc --help | false` [rust-lang#34376]. - [rust-lang#49606] mitigated [rust-lang#34376] by adding an explicit signal handler to `rustc_driver` register a sigpipe handler with `SIG_DFL` which will cause the binary using `rustc_driver` to terminate if `rustc_driver::set_sigpipe_handler()` is called. `rustc`'s main binary wrapper uses `rustc_driver::set_sigpipe_handler()`, and so does `rustdoc`. - A more universal way to set sigpipe behavior for Unix was introduced as part of [rust-lang#97889], i.e. `# [unix_sigpipe = "sig_dfl"]` attribute. - [rust-lang#102587] migrated `rustc` to use `#[unix_sigpipe = "sig_dfl"]` instead of `rustc_driver::set_sigpipe_handler`. - [rust-lang#103495] migrated `rustdoc` to use `#[unix_sigpipe = "sig_dfl"]` instead of `rustc_driver::set_sigpipe_handler`. `rustc_driver::set_sigpipe_handler` was removed. - Following concerns about sigpipe setting UI in [rust-lang#97889], the UI for specifying sigpipe behavior was changed in [rust-lang#124480] from `#[unix_sigpipe = "sig_dfl"]` attribute to the commmand line flag `-Zon-broken-pipe=kill`. - In the same PR, `#[unix_sigpipe = "sig_dfl"]` were removed from `rustc` and `rustdoc` main binary crate entry points in favor of the command line flag. Kill-process-on-broken-pipe behavior was preserved by adding `-Zon-broken-pipe=kill` for `rustdoc` tool build step and `rustc` during compile steps. - [rust-lang#126934] added `-Zon-broken-pipe=kill` for tool builds *except* for cargo to help with some miri tests because at the time the PR was written, this would lead to a couple of cargo test failures. Conditionally setting `RUSTFLAGS` can lead to tool build invalidation, e.g. building `cargo` without `-Zon-broken-pipe=kill` but `clippy` with the flag can lead to invalidation of the tool build cache. This is not a problem at the time, because nothing (not even miri) tests built stage 1 cargo (all used initial cargo). - In [rust-lang#130634] we found out that `run-make` tests like `compiler-builtins` needed stage 1 cargo, not just beta bootstrap cargo, because there can be changes that are present in stage 1 cargo but absent in beta cargo, which was blocking a beta backport. - [rust-lang#130642] and later [rust-lang#130739] now build stage 1 cargo. And as previously mentioned, since `-Zon-broken-pipe=kill` was specifically *not* set for cargo, this caused tool build cache invalidation meaning rebuilds of stage 1 even if nothing in source was changed due to differing `RUSTFLAGS` since `run-make` also builds `rustdoc` and such [rust-lang#130980]. [rust-lang#34376]: rust-lang#34376 [rust-lang#49606]: rust-lang#49606 [rust-lang#97889]: rust-lang#97889 [rust-lang#102587]: rust-lang#102587 [rust-lang#103495]: rust-lang#103495 [rust-lang#124480]: rust-lang#124480 [rust-lang#130634]: rust-lang#130634 [rust-lang#130642]: rust-lang#130642 [rust-lang#130739]: rust-lang#130739 [rust-lang#130980]: rust-lang#130980 [rust-lang#131059]: rust-lang#131059 [^1]: rust-lang#131059 (comment) r? ``@onur-ozkan`` (or bootstrap)
Rollup merge of rust-lang#131108 - jieyouxu:revert-broken-pipe, r=onur-ozkan Revert rust-lang#131060 "Drop conditionally applied cargo `-Zon-broken-pipe=kill` flags" In [rust-lang#131059] we found out that `-Zon-broken-pipe=kill` is actually **load-bearing**[^1] for (at least) `rustc` and `rustdoc` to have the kill-process-on-broken-pipe behavior, e.g. `rustc --print=sysroot | false` will ICE and `rustdoc --print=sysroot | false` will panic on a broken pipe. This PR reverts 5a7058c (reverts PR rust-lang#131060) in favor of a future fix to *unconditionally* apply `-Zon-broken-pipe=kill` to tool builds and also not drop the `-Zon-broken-pipe=kill` flag for rustc binary builds. I could not figure out how to write a regression test for the `rustc --print=sysroot | false` behavior on Unix, so this is a plain revert for now. This revert will unfortunately reintroduce rust-lang#130980 until we fix it again with the different approach. See more details at <rust-lang#131059 (comment)> and in the timeline below. ### Timeline of kill-process-on-broken-pipe behavior changes See [`unix_sigpipe` tracking issue rust-lang#97889][rust-lang#97889] for more context around unix sigpipe handling. - From the very beginning since 2014, Rust binaries by default use `sig_ign`. This meant that if output pipe is broken yet the program tries to use `println!` and such, there will be a broken pipe panic from std. This lead to ICEs from e.g. `rustc --help | false` [rust-lang#34376]. - [rust-lang#49606] mitigated [rust-lang#34376] by adding an explicit signal handler to `rustc_driver` register a sigpipe handler with `SIG_DFL` which will cause the binary using `rustc_driver` to terminate if `rustc_driver::set_sigpipe_handler()` is called. `rustc`'s main binary wrapper uses `rustc_driver::set_sigpipe_handler()`, and so does `rustdoc`. - A more universal way to set sigpipe behavior for Unix was introduced as part of [rust-lang#97889], i.e. `# [unix_sigpipe = "sig_dfl"]` attribute. - [rust-lang#102587] migrated `rustc` to use `#[unix_sigpipe = "sig_dfl"]` instead of `rustc_driver::set_sigpipe_handler`. - [rust-lang#103495] migrated `rustdoc` to use `#[unix_sigpipe = "sig_dfl"]` instead of `rustc_driver::set_sigpipe_handler`. `rustc_driver::set_sigpipe_handler` was removed. - Following concerns about sigpipe setting UI in [rust-lang#97889], the UI for specifying sigpipe behavior was changed in [rust-lang#124480] from `#[unix_sigpipe = "sig_dfl"]` attribute to the commmand line flag `-Zon-broken-pipe=kill`. - In the same PR, `#[unix_sigpipe = "sig_dfl"]` were removed from `rustc` and `rustdoc` main binary crate entry points in favor of the command line flag. Kill-process-on-broken-pipe behavior was preserved by adding `-Zon-broken-pipe=kill` for `rustdoc` tool build step and `rustc` during compile steps. - [rust-lang#126934] added `-Zon-broken-pipe=kill` for tool builds *except* for cargo to help with some miri tests because at the time the PR was written, this would lead to a couple of cargo test failures. Conditionally setting `RUSTFLAGS` can lead to tool build invalidation, e.g. building `cargo` without `-Zon-broken-pipe=kill` but `clippy` with the flag can lead to invalidation of the tool build cache. This is not a problem at the time, because nothing (not even miri) tests built stage 1 cargo (all used initial cargo). - In [rust-lang#130634] we found out that `run-make` tests like `compiler-builtins` needed stage 1 cargo, not just beta bootstrap cargo, because there can be changes that are present in stage 1 cargo but absent in beta cargo, which was blocking a beta backport. - [rust-lang#130642] and later [rust-lang#130739] now build stage 1 cargo. And as previously mentioned, since `-Zon-broken-pipe=kill` was specifically *not* set for cargo, this caused tool build cache invalidation meaning rebuilds of stage 1 even if nothing in source was changed due to differing `RUSTFLAGS` since `run-make` also builds `rustdoc` and such [rust-lang#130980]. [rust-lang#34376]: rust-lang#34376 [rust-lang#49606]: rust-lang#49606 [rust-lang#97889]: rust-lang#97889 [rust-lang#102587]: rust-lang#102587 [rust-lang#103495]: rust-lang#103495 [rust-lang#124480]: rust-lang#124480 [rust-lang#130634]: rust-lang#130634 [rust-lang#130642]: rust-lang#130642 [rust-lang#130739]: rust-lang#130739 [rust-lang#130980]: rust-lang#130980 [rust-lang#131059]: rust-lang#131059 [^1]: rust-lang#131059 (comment) r? ``@onur-ozkan`` (or bootstrap)
Revert #131060 "Drop conditionally applied cargo `-Zon-broken-pipe=kill` flags" In [#131059] we found out that `-Zon-broken-pipe=kill` is actually **load-bearing**[^1] for (at least) `rustc` and `rustdoc` to have the kill-process-on-broken-pipe behavior, e.g. `rustc --print=sysroot | false` will ICE and `rustdoc --print=sysroot | false` will panic on a broken pipe. This PR reverts 5a7058c5a542ec42d1fa9b524f7b4f7d6845d1e9 (reverts PR #131060) in favor of a future fix to *unconditionally* apply `-Zon-broken-pipe=kill` to tool builds and also not drop the `-Zon-broken-pipe=kill` flag for rustc binary builds. I could not figure out how to write a regression test for the `rustc --print=sysroot | false` behavior on Unix, so this is a plain revert for now. This revert will unfortunately reintroduce #130980 until we fix it again with the different approach. See more details at <rust-lang/rust#131059 (comment)> and in the timeline below. ### Timeline of kill-process-on-broken-pipe behavior changes See [`unix_sigpipe` tracking issue #97889][#97889] for more context around unix sigpipe handling. - From the very beginning since 2014, Rust binaries by default use `sig_ign`. This meant that if output pipe is broken yet the program tries to use `println!` and such, there will be a broken pipe panic from std. This lead to ICEs from e.g. `rustc --help | false` [#34376]. - [#49606] mitigated [#34376] by adding an explicit signal handler to `rustc_driver` register a sigpipe handler with `SIG_DFL` which will cause the binary using `rustc_driver` to terminate if `rustc_driver::set_sigpipe_handler()` is called. `rustc`'s main binary wrapper uses `rustc_driver::set_sigpipe_handler()`, and so does `rustdoc`. - A more universal way to set sigpipe behavior for Unix was introduced as part of [#97889], i.e. `# [unix_sigpipe = "sig_dfl"]` attribute. - [#102587] migrated `rustc` to use `#[unix_sigpipe = "sig_dfl"]` instead of `rustc_driver::set_sigpipe_handler`. - [#103495] migrated `rustdoc` to use `#[unix_sigpipe = "sig_dfl"]` instead of `rustc_driver::set_sigpipe_handler`. `rustc_driver::set_sigpipe_handler` was removed. - Following concerns about sigpipe setting UI in [#97889], the UI for specifying sigpipe behavior was changed in [#124480] from `#[unix_sigpipe = "sig_dfl"]` attribute to the commmand line flag `-Zon-broken-pipe=kill`. - In the same PR, `#[unix_sigpipe = "sig_dfl"]` were removed from `rustc` and `rustdoc` main binary crate entry points in favor of the command line flag. Kill-process-on-broken-pipe behavior was preserved by adding `-Zon-broken-pipe=kill` for `rustdoc` tool build step and `rustc` during compile steps. - [#126934] added `-Zon-broken-pipe=kill` for tool builds *except* for cargo to help with some miri tests because at the time the PR was written, this would lead to a couple of cargo test failures. Conditionally setting `RUSTFLAGS` can lead to tool build invalidation, e.g. building `cargo` without `-Zon-broken-pipe=kill` but `clippy` with the flag can lead to invalidation of the tool build cache. This is not a problem at the time, because nothing (not even miri) tests built stage 1 cargo (all used initial cargo). - In [#130634] we found out that `run-make` tests like `compiler-builtins` needed stage 1 cargo, not just beta bootstrap cargo, because there can be changes that are present in stage 1 cargo but absent in beta cargo, which was blocking a beta backport. - [#130642] and later [#130739] now build stage 1 cargo. And as previously mentioned, since `-Zon-broken-pipe=kill` was specifically *not* set for cargo, this caused tool build cache invalidation meaning rebuilds of stage 1 even if nothing in source was changed due to differing `RUSTFLAGS` since `run-make` also builds `rustdoc` and such [#130980]. [#34376]: rust-lang/rust#34376 [#49606]: rust-lang/rust#49606 [#97889]: rust-lang/rust#97889 [#102587]: rust-lang/rust#102587 [#103495]: rust-lang/rust#103495 [#124480]: rust-lang/rust#124480 [#130634]: rust-lang/rust#130634 [#130642]: rust-lang/rust#130642 [#130739]: rust-lang/rust#130739 [#130980]: rust-lang/rust#130980 [#131059]: rust-lang/rust#131059 [^1]: rust-lang/rust#131059 (comment) r? ``@onur-ozkan`` (or bootstrap)
As the private
std::io::print_to
panics if there is an I/O error, which is used byprintln!
, the compiler would ICE if one attempted to use a broken pipe (e.g.rustc --help | false
). This introduces a new (private) macrotry_println!
which allows us to avoid this.As a side note, it seems this macro might be useful publicly (and actually there seems to be a crate specifically for this purpose), though that can probably be left for a future discussion.
One slight alternative approach would be to simply early exit without an error (i.e. exit code
0
), which this comment suggests is the usual approach. I've opted not to take that approach initially, because I think it's more helpful to know when there is a broken pipe.Fixes #34376.