Skip to content

Commit db572f4

Browse files
committed
Send file and line to Godot on panic
1 parent 994093f commit db572f4

File tree

1 file changed

+38
-2
lines changed

1 file changed

+38
-2
lines changed

godot-core/src/lib.rs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ pub mod private {
4343
#[allow(non_camel_case_types)]
4444
pub trait You_forgot_the_attribute__godot_api {}
4545

46+
use std::sync::{Arc, Mutex};
47+
4648
pub use crate::gen::classes::class_macros;
4749
pub use crate::registry::{callbacks, ClassPlugin, ErasedRegisterFn, PluginComponent};
4850
pub use crate::storage::as_storage;
@@ -68,6 +70,11 @@ pub mod private {
6870
}
6971
}
7072

73+
struct GodotPanicInfo {
74+
line: u32,
75+
file: String,
76+
}
77+
7178
/// Executes `code`. If a panic is thrown, it is caught and an error message is printed to Godot.
7279
///
7380
/// Returns `None` if a panic occurred, and `Some(result)` with the result of `code` otherwise.
@@ -77,14 +84,43 @@ pub mod private {
7784
F: FnOnce() -> R + std::panic::UnwindSafe,
7885
S: std::fmt::Display,
7986
{
80-
match std::panic::catch_unwind(code) {
87+
let info: Arc<Mutex<Option<GodotPanicInfo>>> = Arc::new(Mutex::new(None));
88+
89+
// Back up previous hook, set new one
90+
let prev_hook = std::panic::take_hook();
91+
{
92+
let info = info.clone();
93+
std::panic::set_hook(Box::new(move |panic_info| {
94+
if let Some(location) = panic_info.location() {
95+
*info.lock().unwrap() = Some(GodotPanicInfo {
96+
file: location.file().to_string(),
97+
line: location.line(),
98+
});
99+
} else {
100+
println!("panic occurred but can't get location information...");
101+
}
102+
}));
103+
}
104+
105+
// Run code that should panic, restore hook
106+
let panic = std::panic::catch_unwind(code);
107+
std::panic::set_hook(prev_hook);
108+
109+
match panic {
81110
Ok(result) => Some(result),
82111
Err(err) => {
83112
// Flush, to make sure previous Rust output (e.g. test announcement, or debug prints during app) have been printed
84113
// TODO write custom panic handler and move this there, before panic backtrace printing
85114
flush_stdout();
86115

87-
log::godot_error!("Rust function panicked. Context: {}", error_context());
116+
let guard = info.lock().unwrap();
117+
let info = guard.as_ref().expect("no panic info available");
118+
log::godot_error!(
119+
"Rust function panicked in file {} at line {}. Context: {}",
120+
info.file,
121+
info.line,
122+
error_context()
123+
);
88124
print_panic(err);
89125
None
90126
}

0 commit comments

Comments
 (0)