From 90ac11d126434104e5d9aa27065fd37eb4446719 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 3 Sep 2015 22:50:04 +0300 Subject: [PATCH 1/2] give rustc its own panic-handling mechanism this is implemented somewhat hackily, but makes rustc work without unwinding --- src/librustc_driver/lib.rs | 126 +++++++++++++++++++++---------------- 1 file changed, 73 insertions(+), 53 deletions(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index bd2b536f907ae..9911cc6812e41 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -26,13 +26,17 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(box_syntax)] +#![feature(const_fn)] #![feature(libc)] #![feature(quote)] +#![feature(rt)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] +#![feature(thread_local)] #![feature(set_stdio)] #![feature(staged_api)] #![feature(vec_push_all)] +#![feature(unmarked_api)] extern crate arena; extern crate flate; @@ -68,14 +72,16 @@ use rustc::lint; use rustc::metadata; use rustc::util::common::time; +use std::any::Any; use std::cmp::Ordering::Equal; use std::env; -use std::io::{self, Read, Write}; +use std::io::{self, Read}; use std::iter::repeat; use std::path::PathBuf; use std::process; -use std::str; -use std::sync::{Arc, Mutex}; +use std::rt; +use std::rt::backtrace; +use std::sync::atomic::{AtomicBool, Ordering}; use std::thread; use rustc::session::early_error; @@ -786,6 +792,62 @@ fn parse_crate_attrs(sess: &Session, input: &Input) -> result.into_iter().collect() } +fn emit_ice(value: &(Any+Send), file: &'static str, line: u32) { + let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None); + + // a .span_bug or .bug call has already printed what + // it wants to print. + if !value.is::() { + let panic_msg : Option<&str> = match value.downcast_ref::<&'static str>() { + Some(s) => Some(s), + None => match value.downcast_ref::() { + Some(s) => Some(&s), + None => None + } + }; + let msg = if let Some(msg) = panic_msg { + format!("unexpected panic at {}:{}: {}", file, line, msg) + } else { + format!("unexpected panic at {}:{}", file, line) + }; + emitter.emit(None, &msg, None, diagnostic::Bug); + } + + let xs = [ + "the compiler unexpectedly panicked. this is a bug.".to_string(), + format!("we would appreciate a bug report: {}", + BUG_REPORT_URL), + ]; + for note in &xs { + emitter.emit(None, ¬e[..], None, diagnostic::Note) + } + if backtrace::log_enabled() { + let _ = backtrace::write(&mut io::stderr()); + } else { + emitter.emit(None, "run with `RUST_BACKTRACE=1` for a backtrace", + None, diagnostic::Note); + } +} + +#[thread_local] +static IS_RUSTC_THREAD: AtomicBool = AtomicBool::new(false); + +/// The rustc panic handler. thread::spawn is not used directly to avoid +/// depending on unwinding. +#[inline(never)] +#[cold] +pub fn rustc_panic_handler(value: &(Any+Send), file: &'static str, line: u32) { + if !IS_RUSTC_THREAD.load(Ordering::SeqCst) { + return; + } + + if !value.is::() { + emit_ice(value, file, line); + } + + ::std::process::exit(101) +} + /// Run a procedure which will detect panics in the compiler and print nicer /// error messages rather than just failing the test. /// @@ -794,17 +856,6 @@ fn parse_crate_attrs(sess: &Session, input: &Input) -> pub fn monitor(f: F) { const STACK_SIZE: usize = 8 * 1024 * 1024; // 8MB - struct Sink(Arc>>); - impl Write for Sink { - fn write(&mut self, data: &[u8]) -> io::Result { - Write::write(&mut *self.0.lock().unwrap(), data) - } - fn flush(&mut self) -> io::Result<()> { Ok(()) } - } - - let data = Arc::new(Mutex::new(Vec::new())); - let err = Sink(data.clone()); - let mut cfg = thread::Builder::new().name("rustc".to_string()); // FIXME: Hacks on hacks. If the env is trying to override the stack size @@ -813,45 +864,13 @@ pub fn monitor(f: F) { cfg = cfg.stack_size(STACK_SIZE); } - match cfg.spawn(move || { io::set_panic(box err); f() }).unwrap().join() { - Ok(()) => { /* fallthrough */ } - Err(value) => { - // Thread panicked without emitting a fatal diagnostic - if !value.is::() { - let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None); - - // a .span_bug or .bug call has already printed what - // it wants to print. - if !value.is::() { - emitter.emit( - None, - "unexpected panic", - None, - diagnostic::Bug); - } - - let xs = [ - "the compiler unexpectedly panicked. this is a bug.".to_string(), - format!("we would appreciate a bug report: {}", - BUG_REPORT_URL), - ]; - for note in &xs { - emitter.emit(None, ¬e[..], None, diagnostic::Note) - } - if let None = env::var_os("RUST_BACKTRACE") { - emitter.emit(None, "run with `RUST_BACKTRACE=1` for a backtrace", - None, diagnostic::Note); - } - - println!("{}", str::from_utf8(&data.lock().unwrap()).unwrap()); - } - - // Panic so the process returns a failure code, but don't pollute the - // output with some unnecessary panic messages, we've already - // printed everything that we needed to. - io::set_panic(box io::sink()); - panic!(); - } + match cfg.spawn(move || { + io::set_panic(box io::sink()); + IS_RUSTC_THREAD.store(true, Ordering::SeqCst); + f() + }).unwrap().join() { + Ok(_) => {} + Err(_) => {} } } @@ -868,6 +887,7 @@ pub fn diagnostics_registry() -> diagnostics::registry::Registry { } pub fn main() { + unsafe { rt::unwind::register(rustc_panic_handler) }; let result = run(env::args().collect()); process::exit(result as i32); } From 3a1277384fa1df8147d2e616d1b540fbdff2c05b Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 3 Sep 2015 22:51:51 +0300 Subject: [PATCH 2/2] use the compiletest from stage2 for stage1 this fixes `make check-stage1` --- mk/tests.mk | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mk/tests.mk b/mk/tests.mk index e0984cfe86f07..c71ac71bd5ad7 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -619,8 +619,10 @@ define DEF_CTEST_VARS # $(3) is the host triple to test # Prerequisites for compiletest tests +# Note that we always use a stage2 compiletest binary; a stage1 +# compiletest is unusable because stage1 binaries can't panic. TEST_SREQ$(1)_T_$(2)_H_$(3) = \ - $$(HBIN$(1)_H_$(3))/compiletest$$(X_$(3)) \ + $$(HBIN2_H_$(3))/compiletest$$(X_$(3)) \ $$(SREQ$(1)_T_$(2)_H_$(3)) # Rules for the cfail/rfail/rpass/bench/perf test runner @@ -742,7 +744,7 @@ $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \ $$(CTEST_DEPS_$(4)_$(1)-T-$(2)-H-$(3)) @$$(call E, run $(4) [$(2)]: $$<) $$(Q)touch $$@.start_time - $$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \ + $$(Q)$$(call CFG_RUN_CTEST_$(2),2,$$<,$(3)) \ $$(CTEST_ARGS$(1)-T-$(2)-H-$(3)-$(4)) \ --logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \ && touch -r $$@.start_time $$@ && rm $$@.start_time