Skip to content

Commit 08585c0

Browse files
abrownalexcrichton
andcommitted
review: catch host errors and exit all threads
Co-authored-by: Alex Crichton <[email protected]>
1 parent a8778f3 commit 08585c0

File tree

1 file changed

+45
-39
lines changed

1 file changed

+45
-39
lines changed

crates/wasi-threads/src/lib.rs

Lines changed: 45 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
//!
33
//! [`wasi-threads`]: https://github.com/WebAssembly/wasi-threads
44
5-
use anyhow::{anyhow, Result};
5+
use anyhow::{anyhow, bail, Result};
66
use rand::Rng;
7+
use std::panic::{catch_unwind, AssertUnwindSafe};
78
use std::sync::Arc;
8-
use wasmtime::{Caller, Linker, Module, SharedMemory, Store};
9+
use std::thread;
10+
use wasmtime::{Caller, Linker, Module, SharedMemory, Store, ValType};
911
use wasmtime_wasi::maybe_exit_on_error;
1012

1113
// This name is a function export designated by the wasi-threads specification:
@@ -36,46 +38,50 @@ impl<T: Clone + Send + 'static> WasiThreadsCtx<T> {
3638
let wasi_thread_id = random_thread_id();
3739
let builder = thread::Builder::new().name(format!("wasi-thread-{}", wasi_thread_id));
3840
builder.spawn(move || {
39-
// Convenience function for printing failures, since the `Thread`
40-
// has no way to report a failure to the outer context.
41-
let fail = |msg: String| {
42-
format!(
43-
"wasi-thread-{} exited unsuccessfully: {}",
44-
wasi_thread_id, msg
45-
)
46-
};
41+
// Catch any panic failures in host code; e.g., if a WASI module
42+
// were to crash, we want all threads to exit, not just this one.
43+
let result = catch_unwind(AssertUnwindSafe(|| {
44+
// Each new instance is created in its own store.
45+
let mut store = Store::new(&module.engine(), host);
4746

48-
// Each new instance is created in its own store.
49-
let mut store = Store::new(&module.engine(), host);
50-
let instance = linker
51-
.instantiate(&mut store, &module)
52-
.expect(&fail("failed to instantiate".into()));
53-
let thread_entry_point = instance
54-
.get_typed_func::<(i32, i32), ()>(&mut store, WASI_ENTRY_POINT)
55-
.expect(&fail(format!(
56-
"failed to find wasi-threads entry point function: {}",
57-
WASI_ENTRY_POINT
58-
)));
47+
// Ideally, we would have already checked much earlier (e.g.,
48+
// `new`) whether the module can be instantiated. Because
49+
// `Linker::instantiate_pre` requires a `Store` and that is only
50+
// available now. TODO:
51+
// https://github.com/bytecodealliance/wasmtime/issues/5675.
52+
let instance = linker.instantiate(&mut store, &module).expect(&format!(
53+
"wasi-thread-{} exited unsuccessfully: failed to instantiate",
54+
wasi_thread_id
55+
));
56+
let thread_entry_point = instance
57+
.get_typed_func::<(i32, i32), ()>(&mut store, WASI_ENTRY_POINT)
58+
.unwrap();
5959

60-
// Start the thread's entry point. Any traps or calls to
61-
// `proc_exit`, by specification, should end execution for all
62-
// threads. This code uses `process::exit` to do so, which is what
63-
// the user expects from the CLI but probably not in a Wasmtime
64-
// embedding.
65-
log::trace!(
66-
"spawned thread id = {}; calling start function `{}` with: {}",
67-
wasi_thread_id,
68-
WASI_ENTRY_POINT,
69-
thread_start_arg
70-
);
71-
match thread_entry_point.call(&mut store, (wasi_thread_id, thread_start_arg)) {
72-
Ok(_) => log::trace!("exiting thread id = {} normally", wasi_thread_id),
73-
Err(e) => {
74-
log::trace!("exiting thread id = {} due to error", wasi_thread_id);
75-
let e = maybe_exit_on_error(e);
76-
eprintln!("Error: {:?}", e);
77-
std::process::exit(1);
60+
// Start the thread's entry point. Any traps or calls to
61+
// `proc_exit`, by specification, should end execution for all
62+
// threads. This code uses `process::exit` to do so, which is what
63+
// the user expects from the CLI but probably not in a Wasmtime
64+
// embedding.
65+
log::trace!(
66+
"spawned thread id = {}; calling start function `{}` with: {}",
67+
wasi_thread_id,
68+
WASI_ENTRY_POINT,
69+
thread_start_arg
70+
);
71+
match thread_entry_point.call(&mut store, (wasi_thread_id, thread_start_arg)) {
72+
Ok(_) => log::trace!("exiting thread id = {} normally", wasi_thread_id),
73+
Err(e) => {
74+
log::trace!("exiting thread id = {} due to error", wasi_thread_id);
75+
let e = maybe_exit_on_error(e);
76+
eprintln!("Error: {:?}", e);
77+
std::process::exit(1);
78+
}
7879
}
80+
}));
81+
82+
if let Err(e) = result {
83+
eprintln!("Error: {:?}", e);
84+
std::process::exit(1);
7985
}
8086
})?;
8187

0 commit comments

Comments
 (0)