@@ -12,19 +12,24 @@ use prelude::v1::*;
1212use io:: prelude:: * ;
1313
1414use any:: Any ;
15+ use cell:: Cell ;
1516use cell:: RefCell ;
17+ use intrinsics;
1618use sys:: stdio:: Stderr ;
1719use sys_common:: backtrace;
1820use sys_common:: thread_info;
19- use sys_common:: unwind;
21+ use sys_common:: util;
22+
23+ thread_local ! { pub static PANIC_COUNT : Cell <usize > = Cell :: new( 0 ) }
2024
2125thread_local ! {
2226 pub static LOCAL_STDERR : RefCell <Option <Box <Write + Send >>> = {
2327 RefCell :: new( None )
2428 }
2529}
2630
27- pub fn on_panic ( obj : & ( Any +Send ) , file : & ' static str , line : u32 ) {
31+ fn log_panic ( obj : & ( Any +Send ) , file : & ' static str , line : u32 ,
32+ log_backtrace : bool ) {
2833 let msg = match obj. downcast_ref :: < & ' static str > ( ) {
2934 Some ( s) => * s,
3035 None => match obj. downcast_ref :: < String > ( ) {
@@ -35,37 +40,59 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
3540 let mut err = Stderr :: new ( ) . ok ( ) ;
3641 let thread = thread_info:: current_thread ( ) ;
3742 let name = thread. as_ref ( ) . and_then ( |t| t. name ( ) ) . unwrap_or ( "<unnamed>" ) ;
43+
44+ let write = |err : & mut :: io:: Write | {
45+ let _ = writeln ! ( err, "thread '{}' panicked at '{}', {}:{}" ,
46+ name, msg, file, line) ;
47+ if log_backtrace {
48+ let _ = backtrace:: write ( err) ;
49+ }
50+ } ;
51+
3852 let prev = LOCAL_STDERR . with ( |s| s. borrow_mut ( ) . take ( ) ) ;
3953 match ( prev, err. as_mut ( ) ) {
4054 ( Some ( mut stderr) , _) => {
41- // FIXME: what to do when the thread printing panics?
42- let _ = writeln ! ( stderr,
43- "thread '{}' panicked at '{}', {}:{}\n " ,
44- name, msg, file, line) ;
45- if backtrace:: log_enabled ( ) {
46- let _ = backtrace:: write ( & mut * stderr) ;
47- }
55+ write ( & mut * stderr) ;
4856 let mut s = Some ( stderr) ;
4957 LOCAL_STDERR . with ( |slot| {
5058 * slot. borrow_mut ( ) = s. take ( ) ;
5159 } ) ;
5260 }
53- ( None , Some ( ref mut err) ) => {
54- let _ = writeln ! ( err, "thread '{}' panicked at '{}', {}:{}" ,
55- name, msg, file, line) ;
56- if backtrace:: log_enabled ( ) {
57- let _ = backtrace:: write ( err) ;
58- }
59- }
61+ ( None , Some ( ref mut err) ) => { write ( err) }
6062 _ => { }
6163 }
64+ }
6265
63- // If this is a double panic, make sure that we printed a backtrace
64- // for this panic.
65- match err {
66- Some ( ref mut err) if unwind:: panicking ( ) && !backtrace:: log_enabled ( ) => {
67- let _ = backtrace:: write ( err) ;
68- }
69- _ => { }
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 ;
69+ s. set ( count) ;
70+ count
71+ } ) ;
72+
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.
78+ if panics >= 3 {
79+ util:: dumb_print ( format_args ! ( "thread panicked while processing \
80+ panic. aborting.") ) ;
81+ unsafe { intrinsics:: abort ( ) }
82+ }
83+
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) ;
88+
89+ if panics >= 2 {
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. \
95+ aborting.") ) ;
96+ unsafe { intrinsics:: abort ( ) }
7097 }
7198}
0 commit comments