Rollup merge of #49606 - varkor:pipe-repair, r=alexcrichton

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](https://github.com/rust-lang/rust/issues/34376#issuecomment-377822526) 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.
This commit is contained in:
kennytm
2018-04-17 01:50:58 +08:00
committed by GitHub
4 changed files with 19 additions and 3 deletions

View File

@@ -547,6 +547,18 @@ fn run_compiler_impl<'a>(args: &[String],
(result, Some(sess)) (result, Some(sess))
} }
#[cfg(unix)]
pub fn set_sigpipe_handler() {
unsafe {
// Set the SIGPIPE signal handler, so that an EPIPE
// will cause rustc to terminate, as expected.
assert!(libc::signal(libc::SIGPIPE, libc::SIG_DFL) != libc::SIG_ERR);
}
}
#[cfg(windows)]
pub fn set_sigpipe_handler() {}
// Extract output directory and file from matches. // Extract output directory and file from matches.
fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) { fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) {
let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o)); let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));

View File

@@ -100,6 +100,7 @@ struct Output {
pub fn main() { pub fn main() {
const STACK_SIZE: usize = 32_000_000; // 32MB const STACK_SIZE: usize = 32_000_000; // 32MB
rustc_driver::set_sigpipe_handler();
env_logger::init(); env_logger::init();
let res = std::thread::Builder::new().stack_size(STACK_SIZE).spawn(move || { let res = std::thread::Builder::new().stack_size(STACK_SIZE).spawn(move || {
syntax::with_globals(move || { syntax::with_globals(move || {

View File

@@ -80,11 +80,11 @@ pub fn init() {
reset_sigpipe(); reset_sigpipe();
} }
#[cfg(not(any(target_os = "emscripten", target_os="fuchsia")))] #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))]
unsafe fn reset_sigpipe() { unsafe fn reset_sigpipe() {
assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
} }
#[cfg(any(target_os = "emscripten", target_os="fuchsia"))] #[cfg(any(target_os = "emscripten", target_os = "fuchsia"))]
unsafe fn reset_sigpipe() {} unsafe fn reset_sigpipe() {}
} }

View File

@@ -23,4 +23,7 @@ extern {}
extern crate rustc_driver; extern crate rustc_driver;
fn main() { rustc_driver::main() } fn main() {
rustc_driver::set_sigpipe_handler();
rustc_driver::main()
}