forked from 1b-agent/opencadstudio-upstream
feat(plugin): wrap external-plugin calls in a panic guard
A buggy external plugin that panicked anywhere — during load (version, register, manifest), during ribbon build / dispatch, or inside an interactive command (prompt, on_point, on_enter, on_object_pick) — took the host down with it (#134). Run every cdylib entry point under catch_unwind so the host stays up: the plugin's call is treated as inert (load fails, dispatch returns "didn't handle it", interactive hooks resolve to Cancel) and a "Plugin <hook> panicked: …" line lands in the command line on the next tick. (#145) Scope is Rust panics across the cdylib boundary, not genuine UB — real isolation (segfault-proof) still requires out-of-process plugins. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
2a260be31d
commit
f860fb39c2
5 files changed
+122
-14
No files matched your search
+21
-7
@@ -226,23 +226,37 @@ impl crate::command::CadCommand for PluginInteractiveAdapter {
|
||||
fn name(&self) -> &'static str {
|
||||
"PLUGIN"
|
||||
}
|
||||
// Every call into the plugin runs under a panic guard (#145): a buggy plugin
|
||||
// that panics mid-command leaves the host running — the command just ends.
|
||||
fn prompt(&self) -> String {
|
||||
self.inner.prompt()
|
||||
crate::plugin::guard("InteractiveCommand::prompt", || self.inner.prompt())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
fn on_point(&mut self, pt: glam::Vec3) -> crate::command::CmdResult {
|
||||
plugin_step_to_result(self.inner.on_point([pt.x as f64, pt.y as f64, pt.z as f64]))
|
||||
crate::plugin::guard("InteractiveCommand::on_point", || {
|
||||
self.inner.on_point([pt.x as f64, pt.y as f64, pt.z as f64])
|
||||
})
|
||||
.map(plugin_step_to_result)
|
||||
.unwrap_or(crate::command::CmdResult::Cancel)
|
||||
}
|
||||
fn on_enter(&mut self) -> crate::command::CmdResult {
|
||||
plugin_step_to_result(self.inner.on_enter())
|
||||
crate::plugin::guard("InteractiveCommand::on_enter", || self.inner.on_enter())
|
||||
.map(plugin_step_to_result)
|
||||
.unwrap_or(crate::command::CmdResult::Cancel)
|
||||
}
|
||||
fn needs_entity_pick(&self) -> bool {
|
||||
self.inner.needs_object_pick()
|
||||
crate::plugin::guard("InteractiveCommand::needs_object_pick", || {
|
||||
self.inner.needs_object_pick()
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
fn on_entity_pick(&mut self, handle: Handle, pt: glam::Vec3) -> crate::command::CmdResult {
|
||||
plugin_step_to_result(
|
||||
crate::plugin::guard("InteractiveCommand::on_object_pick", || {
|
||||
self.inner
|
||||
.on_object_pick(handle, [pt.x as f64, pt.y as f64, pt.z as f64]),
|
||||
)
|
||||
.on_object_pick(handle, [pt.x as f64, pt.y as f64, pt.z as f64])
|
||||
})
|
||||
.map(plugin_step_to_result)
|
||||
.unwrap_or(crate::command::CmdResult::Cancel)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -414,6 +414,14 @@ impl OpenCADStudio {
|
||||
}
|
||||
}
|
||||
|
||||
// Surface any plugin-guard panic messages that piled up since
|
||||
// the last tick (the host singleton isn't reachable from inside
|
||||
// the plugin hooks, so they queue and we flush here). (#145)
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
for msg in crate::plugin::drain_errors() {
|
||||
self.command_line.push_error(&msg);
|
||||
}
|
||||
|
||||
Task::none()
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user