This repo has a test program that’s used to compare the behavior of the coredump crate with the built in panic = abort
behavior. The program itself sets up some configuration as requested and then panics. There’s a wrapper script run_all.sh
that runs all combinations of configuration:
-
panic = abort
orpanic = unwind
(see Cargo’s panic configuration) -
use the coredump crate (true/false)
-
whether the program tries to catch the panic (true/false)
In all cases we set RUST_BACKTRACE=full to show the full stack trace.
Notes:
-
In all configurations, the stack trace is pretty-printed before the process dumps core.
-
In all of the core files generated,
foo
andbar
appear on the stack (i.e., in no case was the stack unwound before generating the core file). -
For the binary (executable) case, the only difference observed between
panic=abort
and enabling thecoredump
crate is which signal terminated the process. Usingcoredump
did not allow a panic to be caught. Note that in these tests,ulimit -c
was already set tounlimited
. The "coredump" crate does reconfigure this to enable core files, so this would be a difference in other environments. -
For the integration test case,
coredump
actually causes a core file to be created, whilepanic = "abort"
is ignored. (Se below.) -
In the integration test version,
panic = abort
has no effect. This is mostly as documented, although as of this writing it’s unclear if this is supposed to be altered by panic-abort-tests (which we do use below). More on this below. -
The panic cannot be caught if either
panic = abort
or the "coredump" crate is enabled, even when the former did not result in generating a core file (e.g., in the integration test). This is consistent with the documentation for catch_unwind, which says that it does not catch panics whenpanic
is notunwind
. It’s perhaps surprising that the panic cannot be caught whenpanic = "unwind"
and the "coredump" crate is enabled, but this is because the "coredump" crate dumps core from the panic hook, which happens before the unwind runtime.
panic strategy | enable "coredump" crate | attempt to catch panic | bash exit status | created core file? | caught panic? |
---|---|---|---|---|---|
unwind |
"coredump" crate disabled |
no catch |
101 (process exited with Rust panic exit code) |
No |
— |
unwind |
"coredump" crate disabled |
catch |
0 (no error because the panic was caught) |
No |
Yes |
unwind |
"coredump" crate enabled |
no catch |
131 (process terminated by signal |
Yes |
— |
unwind |
"coredump" crate enabled |
catch |
131 (process terminated by signal |
Yes |
No |
abort |
"coredump" crate disabled |
no catch |
134 (process terminated by signal |
Yes |
— |
abort |
"coredump" crate disabled |
catch |
134 (process terminated by signal |
Yes |
No |
abort |
"coredump" crate enabled |
no catch |
131 (process terminated by signal |
Yes |
— |
abort |
"coredump" crate enabled |
catch |
131 (process terminated by signal |
Yes |
No |
panic strategy | enable "coredump" crate | attempt to catch panic | bash exit status | created core file? | caught panic? |
---|---|---|---|---|---|
unwind |
"coredump" crate disabled |
no catch |
test runner status 101 (test runner handles panic) |
No |
— |
unwind |
"coredump" crate disabled |
catch |
0 (no error because the panic was caught) |
No |
Yes |
unwind |
"coredump" crate enabled |
no catch |
test runner status 101, reports process itself terminated by signal |
Yes |
— |
unwind |
"coredump" crate enabled |
catch |
test runner status 101, reports process itself terminated by signal |
Yes |
No |
abort |
"coredump" crate disabled |
no catch |
test runner status 101 (test runner handles panic) |
No |
— |
abort |
"coredump" crate disabled |
catch |
test runner status 101 (test runner handles panic) |
No |
No |
abort |
"coredump" crate enabled |
no catch |
test runner status 101 (test runner handles panic) |
No |
— |
abort |
"coredump" crate enabled |
catch |
test runner status 101 (test runner handles panic) |
No |
No |
This behavior was a little surprising for the integration test case. I dug into the implementation a bit. Before running our test function, the Rust test runner creates a panic hook that records the result, runs any previous hook (which we would not expect to be there, even when we enable "coredump", because that happens later), and then potentially exits the process. Now, if we’ve enabled the "coredump" crate, it will invoke the existing hook, then raise SIGQUIT
. So the expected behavior is that the process would be terminated by SIGQUIT
, and that’s what we see.
Why doesn’t panic = abort
work even with -Z panic-abort-tests
? I have confirmed that for my test program, __rust_start_panic
refers to the abort
implementation, despite the warning in the output that the value is being ignored. (Cargo bug?) However, the hook that gets installed by the test runner in this case (see above) explicitly exits the process, and this runs before the real panic runtime, so we never get to the abort call.