Skip to content

Commit 5c01316

Browse files
committed
Add regression test for rustc/rustdoc broken pipe ICEs
1 parent 03abf67 commit 5c01316

2 files changed

Lines changed: 75 additions & 4 deletions

File tree

‎src/bootstrap/src/bin/rustc.rs‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,8 @@ fn main() {
136136
cmd.args(lint_flags.split_whitespace());
137137
}
138138

139-
// Conditionally pass `-Zon-broken-pipe=kill` to rustc bin shim when this shim is *not* used to
140-
// build cargo itself, i.e. set `-Zon-broken-pipe=kill` only when building non-cargo tools.
141-
//
142-
// See <https://github.com/rust-lang/rust/issues/131059> for more context.
139+
// Conditionally pass `-Zon-broken-pipe=kill` to underlying rustc. Not all binaries want
140+
// `-Zon-broken-pipe=kill`, which includes cargo itself.
143141
if env::var_os("FORCE_ON_BROKEN_PIPE_KILL").is_some(){
144142
cmd.arg("-Z").arg("on-broken-pipe=kill");
145143
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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+
enumBinary{
17+
Rustc,
18+
Rustdoc,
19+
}
20+
21+
fncheck_broken_pipe_handled_gracefully(bin:Binary,mutcmd:Command){
22+
let(reader, writer) = std::pipe::pipe().unwrap();
23+
drop(reader);// close read-end
24+
cmd.stdout(writer).stderr(Stdio::piped());
25+
26+
letmut child = cmd.spawn().unwrap();
27+
28+
letmut 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+
constPANIC_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+
fnmain(){
66+
letmut rustc = Command::new(env_var("RUSTC"));
67+
rustc.arg("--print=sysroot");
68+
check_broken_pipe_handled_gracefully(Binary::Rustc, rustc);
69+
70+
letmut rustdoc = Command::new(env_var("RUSTDOC"));
71+
rustdoc.arg("--version");
72+
check_broken_pipe_handled_gracefully(Binary::Rustdoc, rustdoc);
73+
}

0 commit comments

Comments
 (0)