1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
18 use sys::stdio::Stderr;
19 use sys_common::backtrace;
20 use sys_common::thread_info;
23 thread_local! { pub static PANIC_COUNT: Cell<usize> = Cell::new(0) }
26 pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = {
31 fn log_panic(obj: &(Any+Send), file: &'static str, line: u32,
32 log_backtrace: bool) {
33 let msg = match obj.downcast_ref::<&'static str>() {
35 None => match obj.downcast_ref::<String>() {
40 let mut err = Stderr::new().ok();
41 let thread = thread_info::current_thread();
42 let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
44 let write = |err: &mut ::io::Write| {
45 let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}",
46 name, msg, file, line);
48 let _ = backtrace::write(err);
52 let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take());
53 match (prev, err.as_mut()) {
54 (Some(mut stderr), _) => {
56 let mut s = Some(stderr);
57 LOCAL_STDERR.with(|slot| {
58 *slot.borrow_mut() = s.take();
61 (None, Some(ref mut err)) => { write(err) }
66 pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
67 let panics = PANIC_COUNT.with(|s| {
68 let count = s.get() + 1;
73 // If this is the third nested call, on_panic triggered the last panic,
74 // otherwise the double-panic check would have aborted the process.
75 // Even if it is likely that on_panic was unable to log the backtrace,
76 // abort immediately to avoid infinite recursion, so that attaching a
77 // debugger provides a useable stacktrace.
79 util::dumb_print(format_args!("thread panicked while processing \
81 unsafe { intrinsics::abort() }
84 // If this is a double panic, make sure that we print a backtrace
85 // for this panic. Otherwise only print it if logging is enabled.
86 let log_backtrace = panics >= 2 || backtrace::log_enabled();
87 log_panic(obj, file, line, log_backtrace);
90 // If a thread panics while it's already unwinding then we
91 // have limited options. Currently our preference is to
92 // just abort. In the future we may consider resuming
93 // unwinding or otherwise exiting the thread cleanly.
94 util::dumb_print(format_args!("thread panicked while panicking. \
96 unsafe { intrinsics::abort() }