Closed QuadnucYard closed 1 month ago
Thanks for reporting!
According to your stacktrace, it happens in this line: https://github.com/godot-rust/gdext/blob/15bc053d67b526aa79abd882219a292579631215/godot-core/src/private.rs#L361-L361
So the PanicInfo
that's usually provided in a panic hook seems to be None
(absent). I don't know how color_backtrace
interferes with the panic system, here you'd need to help me to see what we need to consider.
Worst case we could just print "no panic info" instead of .expect()
, but it would be nice to go to the bottom of this :thinking:
Besides, my previous tests triggered a panic in the initialize
of SceneTree
.
If the panic occurs elsewhere (during process
), only ERROR: ...
with the panic information will be printed out (no backtrace), even if with color-backtrace installed.
Such panic cannot be caught by the debugger either, which is terrible for debugging.
It seems that color-backtrace
just set a new panic hook but not take the previous one, so it is the only panic handler.
It employs backtrace
library to collect backtrace frames, which should do nothing with panic.
This hook is taken when runing process
, so no backtrace is printed. But why initialize
appears differently?
I didn't see this eprintln
take effect. So the new hook doesn't work in initialize
?
I hope to get a pretty backtrace (from color-backtrace, printed to stdout) during debugging. It needn't to be printed to godot debugger, considering:
godot_print
always has a single color (red if ERROR).godot_print
is also printed to stdout, just a poor replica.But when released, I just need to collect plain backtrace as crash logs.
I take the following code from gdnative. It somehow works well in 0.1.1 (or earlier?), and I can see the crash from godot logs.
fn init_panic_hook() {
let old_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |panic_info| {
let loc_string;
if let Some(location) = panic_info.location() {
loc_string = format!("file '{}' at line {}", location.file(), location.line());
} else {
loc_string = "unknown location".to_owned()
}
let error_message;
if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
error_message = format!("[RUST] {loc_string}: panic occurred: {s:?}");
} else if let Some(s) = panic_info.payload().downcast_ref::<String>() {
error_message = format!("[RUST] {loc_string}: panic occurred: {s:?}");
} else {
error_message = format!("[RUST] {loc_string}: unknown panic occurred");
}
godot_error!("{}", error_message);
if let Ok(str) = format_backtrace_string() {
godot_print!("{str}");
}
(*(old_hook.as_ref()))(panic_info);
}));
}
fn format_backtrace_string() -> Result<String, std::io::Error> {
use backtrace::Backtrace;
use color_backtrace::{termcolor::NoColor, BacktracePrinter};
let mut out = NoColor::new(vec![]);
BacktracePrinter::new().print_trace(&Backtrace::new(), &mut out)?;
Ok(String::from_utf8(out.into_inner()).unwrap())
}
Besides, my previous tests triggered a panic in the
initialize
ofSceneTree
. If the panic occurs elsewhere (duringprocess
), onlyERROR: ...
with the panic information will be printed out (no backtrace), even if with color-backtrace installed.Such panic cannot be caught by the debugger either, which is terrible for debugging.
This probably falls under https://github.com/godot-rust/gdext/issues/411. Fully agree that we should look for ways to trigger the debugger.
It seems that
color-backtrace
just set a new panic hook but not take the previous one, so it is the only panic handler. It employsbacktrace
library to collect backtrace frames, which should do nothing with panic.
Hm, independently of this issue in gdext, do you think that's something worth reporting to color-backtrace
?
This hook is taken when runing
process
, so no backtrace is printed. But whyinitialize
appears differently?
Good question, do you think this should be unified somehow?
I take the following code from gdnative. It somehow works well in 0.1.1 (or earlier?), and I can see the crash from godot logs.
The main takeaway here seems to be calling the previous hook, right?
Btw, you seem to have quite a concrete idea how to improve panic handling. Would you be interested in helping out with a pull request? :slightly_smiling_face:
@Bromeon I'm glad to offer some help, but sorry I don't have much experience with Rust (especially runtime) and I'm not familiar with foundations of gdext yet...
Let us know if we can help somehow. Our Discord community is also quite friendly in case you need some onboarding 🙂
If not, that's also fair, just keep in mind that I'm currently addressing many foundational parts for v0.2, and likely won't get around looking into very specific integrations (like color-backtrace or #832) for several months 😉
Oh, I further noticed that my color-backtrace is unexpectedly stripped sometime.
In a panic triggered by a custom callable (used to connect to a pressed
signal), my panic handle is gone. Only a large number of bare stack frames (but no [ERROR]
) are printed, as if I haven't set a panic hook.
So the only [ERROR]
output I saw before may be because there is only that panic handle left.
@QuadnucYard note that in the meantime, we disabled panic hooks in Release mode (https://github.com/godot-rust/gdext/pull/889). So it might be that Release mode already has the issue solved.
Other than that, do you plan to investigate this? I don't see any concrete actionables on gdext side, as it's not even clear whether it's color-backtrace or gdext misbehaving. If not, I would probably close this.
I just run this code:
It will print unexpected panic information after normal information.
It seems alright in 0.1.1 with the output below, despite an issue with
unwind
:But on more unexpected stack backtrace from panic (
no panic info available
) occurs in 0.1.2 and 0.1.3 as belowIf I do not use color_backtrace, only a simple piece of information is given (v0.1.3). And no backtrace is printed.
Rust version:
rustc 1.82.0-nightly (7120fdac7 2024-07-25)
.color-backtrace=0.6.1
Run withRUST_BACKTRACE=full
.So is this a bug, or does it require additional setting up panic handling? Thank you for your response!