mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-12-23 10:11:54 +00:00
Sandbox node graph execution on native targets and attempt recovery from panics on Wasm (#1846)
* Test out wasm unwinding * Implement panic catching for native targets * Hack in support for recovering panics in wasm * Keep debug info in release builds * Check for DynAnyNode in Backtrace because that can't be inlined as well * Improve error dialog * Use a mutex for storing the frontend state instead of a RefCell * Code review * Update crash text --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
06177597ae
commit
5b1d3a0ae4
8 changed files with 110 additions and 46 deletions
|
|
@ -10,6 +10,7 @@ use graph_craft::Type;
|
|||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::error::Error;
|
||||
use std::panic::UnwindSafe;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// An executor of a node graph that does not require an online compilation server, and instead uses `Box<dyn ...>`.
|
||||
|
|
@ -102,9 +103,22 @@ impl DynamicExecutor {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, I: StaticType + 'static + Send + Sync> Executor<I, TaggedValue> for &'a DynamicExecutor {
|
||||
impl<'a, I: StaticType + 'static + Send + Sync + std::panic::UnwindSafe> Executor<I, TaggedValue> for &'a DynamicExecutor {
|
||||
fn execute(&self, input: I) -> LocalFuture<Result<TaggedValue, Box<dyn Error>>> {
|
||||
Box::pin(async move { self.tree.eval_tagged_value(self.output, input).await.map_err(|e| e.into()) })
|
||||
Box::pin(async move {
|
||||
use futures::FutureExt;
|
||||
|
||||
let result = self.tree.eval_tagged_value(self.output, input);
|
||||
let wrapped_result = std::panic::AssertUnwindSafe(result).catch_unwind().await;
|
||||
|
||||
match wrapped_result {
|
||||
Ok(result) => result.map_err(|e| e.into()),
|
||||
Err(e) => {
|
||||
Box::leak(e);
|
||||
Err("Node graph execution paniced".into())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -176,7 +190,7 @@ impl BorrowTree {
|
|||
}
|
||||
/// Evaluate the output node of the [`BorrowTree`] and cast it to a tagged value.
|
||||
/// This ensures that no borrowed data can escape the node graph.
|
||||
pub async fn eval_tagged_value<I: StaticType + 'static + Send + Sync>(&self, id: NodeId, input: I) -> Result<TaggedValue, String> {
|
||||
pub async fn eval_tagged_value<I: StaticType + 'static + Send + Sync + UnwindSafe>(&self, id: NodeId, input: I) -> Result<TaggedValue, String> {
|
||||
let node = self.nodes.get(&id).cloned().ok_or("Output node not found in executor")?;
|
||||
let output = node.eval(Box::new(input));
|
||||
TaggedValue::try_from_any(output.await)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue