diff --git a/jay-config/src/_private/client.rs b/jay-config/src/_private/client.rs index d78c76df..67d6b7f2 100644 --- a/jay-config/src/_private/client.rs +++ b/jay-config/src/_private/client.rs @@ -28,6 +28,7 @@ use { future::Future, mem, ops::Deref, + panic::{catch_unwind, AssertUnwindSafe}, pin::Pin, ptr, rc::Rc, @@ -49,11 +50,17 @@ fn cb(f: F) -> Callback { fn run_cb(name: &str, cb: &Callback, t: T) { match cb.try_borrow_mut() { - Ok(mut cb) => cb(t), + Ok(mut cb) => ignore_panic(name, || cb(t)), Err(_) => log::error!("Cannot invoke {name} callback because it is already running"), } } +fn ignore_panic(name: &str, f: impl FnOnce()) { + if catch_unwind(AssertUnwindSafe(f)).is_err() { + log::error!("A panic occurred in a {name} callback"); + } +} + pub(crate) struct Client { configure: extern "C" fn(), srv_data: *const u8, @@ -863,10 +870,18 @@ impl Client { if let Some(fut) = fut { let mut fut = fut.borrow_mut(); let fut = &mut *fut; - if let Poll::Ready(()) = + let res = catch_unwind(AssertUnwindSafe(|| { fut.task.as_mut().poll(&mut Context::from_waker(&fut.waker)) - { - futures.tasks.borrow_mut().remove(&id); + })); + match res { + Err(_) => { + log::error!("A task panicked"); + futures.tasks.borrow_mut().remove(&id); + } + Ok(Poll::Ready(())) => { + futures.tasks.borrow_mut().remove(&id); + } + Ok(_) => {} } } } @@ -966,7 +981,7 @@ impl Client { } ServerMessage::GraphicsInitialized => { if let Some(handler) = self.on_graphics_initialized.take() { - handler(); + ignore_panic("graphics initialized", handler); } } ServerMessage::Clear => { @@ -992,7 +1007,7 @@ impl Client { } ServerMessage::DevicesEnumerated => { if let Some(handler) = self.on_devices_enumerated.take() { - handler(); + ignore_panic("devices enumerated", handler); } } ServerMessage::InterestReady { id, writable, res } => {