|
| 1 | +//! Check that `rustc` and `rustdoc` does not ICE upon encountering a broken pipe due to unhandled |
| 2 | +//! panics from raw std `println!` usages. |
| 3 | +//! |
| 4 | +//! Regression test for <https://github.com/rust-lang/rust/issues/34376>. |
| 5 | +
|
| 6 | +//@ ignore-cross-compile (needs to run test binary) |
| 7 | + |
| 8 | +#![feature(anonymous_pipe)] |
| 9 | + |
| 10 | +use std::io::Read; |
| 11 | +use std::process::{Command, Stdio}; |
| 12 | + |
| 13 | +use run_make_support::env_var; |
| 14 | + |
| 15 | +#[derive(Debug, PartialEq)] |
| 16 | +enum Binary { |
| 17 | + Rustc, |
| 18 | + Rustdoc, |
| 19 | +} |
| 20 | + |
| 21 | +fn check_broken_pipe_handled_gracefully(bin: Binary, mut cmd: Command) { |
| 22 | + let (reader, writer) = std::pipe::pipe().unwrap(); |
| 23 | + drop(reader); // close read-end |
| 24 | + cmd.stdout(writer).stderr(Stdio::piped()); |
| 25 | + |
| 26 | + let mut child = cmd.spawn().unwrap(); |
| 27 | + |
| 28 | + let mut stderr = String::new(); |
| 29 | + child.stderr.as_mut().unwrap().read_to_string(&mut stderr).unwrap(); |
| 30 | + let status = child.wait().unwrap(); |
| 31 | + |
| 32 | + assert!(!status.success(), "{bin:?} unexpectedly succeeded"); |
| 33 | + |
| 34 | + const PANIC_ICE_EXIT_CODE: i32 = 101; |
| 35 | + |
| 36 | + #[cfg(not(windows))] |
| 37 | + { |
| 38 | + // On non-Windows, rustc/rustdoc built with `-Zon-broken-pipe=kill` shouldn't have an exit |
| 39 | + // code of 101 because it should have an wait status that corresponds to SIGPIPE signal |
| 40 | + // number. |
| 41 | + assert_ne!(status.code(), Some(PANIC_ICE_EXIT_CODE), "{bin:?}"); |
| 42 | + // And the stderr should be empty because rustc/rustdoc should've gotten killed. |
| 43 | + assert!(stderr.is_empty(), "{bin:?} stderr:\n{}", stderr); |
| 44 | + } |
| 45 | + |
| 46 | + #[cfg(windows)] |
| 47 | + { |
| 48 | + match bin { |
| 49 | + // On Windows, rustc has a paper that propagates the panic exit code of 101 but converts |
| 50 | + // broken pipe errors into fatal errors instead of ICEs. |
| 51 | + Binary::Rustc => { |
| 52 | + assert_eq!(status.code(), Some(PANIC_ICE_EXIT_CODE), "{bin:?}"); |
| 53 | + // But make sure it doesn't manifest as an ICE. |
| 54 | + assert!(!stderr.contains("internal compiler error"), "{bin:?} ICE'd"); |
| 55 | + } |
| 56 | + // On Windows, rustdoc seems to cleanly exit with exit code of 1. |
| 57 | + Binary::Rustdoc => { |
| 58 | + assert_eq!(status.code(), Some(1), "{bin:?}"); |
| 59 | + assert!(!stderr.contains("panic"), "{bin:?} stderr contains panic"); |
| 60 | + } |
| 61 | + } |
| 62 | + } |
| 63 | +} |
| 64 | + |
| 65 | +fn main() { |
| 66 | + let mut rustc = Command::new(env_var("RUSTC")); |
| 67 | + rustc.arg("--print=sysroot"); |
| 68 | + check_broken_pipe_handled_gracefully(Binary::Rustc, rustc); |
| 69 | + |
| 70 | + let mut rustdoc = Command::new(env_var("RUSTDOC")); |
| 71 | + rustdoc.arg("--version"); |
| 72 | + check_broken_pipe_handled_gracefully(Binary::Rustdoc, rustdoc); |
| 73 | +} |
0 commit comments