//! Check that `rustc` and `rustdoc` does not ICE upon encountering a broken pipe due to unhandled //! panics from raw std `println!` usages. //! //! Regression test for . //@ ignore-cross-compile (needs to run test binary) //@ ignore-apple // FIXME(#131436): on macOS rustc is still reporting the std broken pipe io error panick but it // doesn't fail with 101 exit status (it terminates with a wait status of SIGPIPE). It doesn't say // Internal Compiler Error strangely, but it doesn't even go through normal diagnostic infra. Very // strange. #![feature(anonymous_pipe)] use std::io::Read; use std::process::{Command, Stdio}; use run_make_support::env_var; #[derive(Debug, PartialEq)] enum Binary { Rustc, Rustdoc, } fn check_broken_pipe_handled_gracefully(bin: Binary, mut cmd: Command) { let (reader, writer) = std::pipe::pipe().unwrap(); drop(reader); // close read-end cmd.stdout(writer).stderr(Stdio::piped()); let mut child = cmd.spawn().unwrap(); let mut stderr = String::new(); child.stderr.as_mut().unwrap().read_to_string(&mut stderr).unwrap(); let status = child.wait().unwrap(); assert!(!status.success(), "{bin:?} unexpectedly succeeded"); const PANIC_ICE_EXIT_CODE: i32 = 101; #[cfg(not(windows))] { // On non-Windows, rustc/rustdoc built with `-Zon-broken-pipe=kill` shouldn't have an exit // code of 101 because it should have an wait status that corresponds to SIGPIPE signal // number. assert_ne!(status.code(), Some(PANIC_ICE_EXIT_CODE), "{bin:?}"); // And the stderr should be empty because rustc/rustdoc should've gotten killed. assert!(stderr.is_empty(), "{bin:?} stderr:\n{}", stderr); } #[cfg(windows)] { match bin { // On Windows, rustc has a paper that propagates the panic exit code of 101 but converts // broken pipe errors into fatal errors instead of ICEs. Binary::Rustc => { assert_eq!(status.code(), Some(PANIC_ICE_EXIT_CODE), "{bin:?}"); // But make sure it doesn't manifest as an ICE. assert!(!stderr.contains("internal compiler error"), "{bin:?} ICE'd"); } // On Windows, rustdoc seems to cleanly exit with exit code of 1. Binary::Rustdoc => { assert_eq!(status.code(), Some(1), "{bin:?}"); assert!(!stderr.contains("panic"), "{bin:?} stderr contains panic"); } } } } fn main() { let mut rustc = Command::new(env_var("RUSTC")); rustc.arg("--print=sysroot"); check_broken_pipe_handled_gracefully(Binary::Rustc, rustc); let mut rustdoc = Command::new(env_var("RUSTDOC")); rustdoc.arg("--version"); check_broken_pipe_handled_gracefully(Binary::Rustdoc, rustdoc); }