Debug 'thread panicked while panicking'?


#1

I know that the ‘thread panicked while panicking’ message is almost certainly evidence of something dumb that I did (wrt the second panic, that is). However, I’m wondering if there’s a way to get Rust to at least print a file/line number before aborting when this happens? I’ve got a large codebase and I’m having difficulty tracking it down.


#2

Valgrind to the rescue! I’m not sure if it will work in all cases of panicking-while-panicking, but at least in my case, running my code under valgrind showed a stack trace of the moment the second panic occurred.


#3

I was curious so I thought I’d check it out on my machine.

$ rustc --version
rustc 1.19.0-nightly (2d4ed8e0c 2017-05-03)

The source code:

$ cat main.rs

struct Foo {}

impl Drop for Foo {
    fn drop(&mut self) {
        panic!("Double panic!");
    }
}

pub fn main() {
    let d = Foo {};
    panic!();
}

And the output:

thread 'main' panicked at 'explicit panic', main.rs:11
note: Run with `RUST_BACKTRACE=1` for a backtrace.
thread 'main' panicked at 'Double panic!', main.rs:5
stack backtrace:
   0:     0x5576b4aef533 - std::sys::imp::backtrace::tracing::imp::unwind_backtrace::h0e14f963e590228b
                               at /checkout/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
   1:     0x5576b4aebf22 - std::sys_common::backtrace::_print::h27334d67e47d33d3
                               at /checkout/src/libstd/sys_common/backtrace.rs:71
   2:     0x5576b4af0d64 - std::panicking::default_hook::{{closure}}::h47b2a7bf24f9ec4b
                               at /checkout/src/libstd/sys_common/backtrace.rs:60
                               at /checkout/src/libstd/panicking.rs:355
   3:     0x5576b4af092b - std::panicking::default_hook::h96a38c23a922ad21
                               at /checkout/src/libstd/panicking.rs:371
   4:     0x5576b4af115b - std::panicking::rust_panic_with_hook::h2e0c66f95442aa5e
                               at /checkout/src/libstd/panicking.rs:549
   5:     0x5576b4ae78c1 - std::panicking::begin_panic::h32add8ccad0c0f8c
   6:     0x5576b4ae7a21 - <main::Foo as core::ops::Drop>::drop::h0772637ccfdbda50
   7:     0x5576b4ae7915 - core::ptr::drop_in_place::hcd339a962d1f7c82
   8:     0x5576b4ae7a6b - main::main::h94cdd750d4114894
   9:     0x5576b4af8c5a - __rust_maybe_catch_panic
                               at /checkout/src/libpanic_unwind/lib.rs:98
  10:     0x5576b4af1791 - std::rt::lang_start::h8126425a59d3b4a0
                               at /checkout/src/libstd/panicking.rs:433
                               at /checkout/src/libstd/panic.rs:361
                               at /checkout/src/libstd/rt.rs:57
  11:     0x5576b4ae7aa9 - main
  12:     0x7f46f2063510 - __libc_start_main
  13:     0x5576b4ae7729 - _start
  14:                0x0 - <unknown>
thread panicked while panicking. aborting.
[2]    27536 illegal hardware instruction (core dumped)  ./main

Looks like it was added some time recently to nightly because I can see the location of both panic!()s.


#4

That example seems to work in 1.17 as well: https://is.gd/3XcZSn

It looks like printing a backtrace on a second panic was added in 1.7: https://github.com/rust-lang/rust/commit/f1148a540a16ba4ba2635403a9b014da9683851b

EDIT: Actually, it existed before that, I’m not sure exactly when.


#5

Huh weird. I think that, in my case, the issue was caused by a SIGSEGV, which in turn caused a panic, which in turn caused a drop to panic… maybe. I’m not positive. I’m writing some very unsafe code, so I’m not really sure. In any case, that might explain why I wasn’t getting a stack trace.


#6

In this case, you should not need to use valgrind, gdb should be enough.


#7

Yeah, either of them works in this case.