about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAndrea Canciani <ranma42@gmail.com>2015-09-24 17:21:29 +0200
committerAndrea Canciani <ranma42@gmail.com>2015-09-24 23:52:13 +0200
commit54c0231b14a71a46e6607255d509457e0df0b8be (patch)
tree41ef410ea263c71bb40005b6aae4c4fbf3615f4a
parentc7b84909b00dcf5f762778b4aa9783770c69416d (diff)
downloadrust-54c0231b14a71a46e6607255d509457e0df0b8be.tar.gz
rust-54c0231b14a71a46e6607255d509457e0df0b8be.zip
Abort earlier upon multi-panics
The double-panic `abort` is run after the logging code, to provide
feedback in case of a double-panic. This means that if the panic
logging fails with a panic, the `abort` might never be reached.

This should not normally occur, but if the `on_panic` function detects
more than 2 panics, aborting *before* logging makes panic handling
somewhat more robust, as it avoids an infinite recursion, which would
eventually crash the process, but also make the problem harder to
debug.

This handles the FIXME about what to do if the thread printing panics.
-rw-r--r--src/libstd/panicking.rs12
1 files changed, 11 insertions, 1 deletions
diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs
index fc242dee99f..2b2af350c99 100644
--- a/src/libstd/panicking.rs
+++ b/src/libstd/panicking.rs
@@ -52,7 +52,6 @@ fn log_panic(obj: &(Any+Send), file: &'static str, line: u32,
     let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take());
     match (prev, err.as_mut()) {
         (Some(mut stderr), _) => {
-            // FIXME: what to do when the thread printing panics?
             write(&mut *stderr);
             let mut s = Some(stderr);
             LOCAL_STDERR.with(|slot| {
@@ -71,6 +70,17 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
         count
     });
 
+    // If this is the third nested call, on_panic triggered the last panic,
+    // otherwise the double-panic check would have aborted the process.
+    // Even if it is likely that on_panic was unable to log the backtrace,
+    // abort immediately to avoid infinite recursion, so that attaching a
+    // debugger provides a useable stacktrace.
+    if panics >= 3 {
+        util::dumb_print(format_args!("thread panicked while processing \
+                                       panic. aborting."));
+        unsafe { intrinsics::abort() }
+    }
+
     // If this is a double panic, make sure that we print a backtrace
     // for this panic. Otherwise only print it if logging is enabled.
     let log_backtrace = panics >= 2 || backtrace::log_enabled();