diff --git a/Cargo.lock b/Cargo.lock index a10370b33f14..f2e2b6d4d43f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3747,6 +3747,7 @@ name = "wasmtime-wasi" version = "7.0.0" dependencies = [ "anyhow", + "libc", "wasi-cap-std-sync", "wasi-common", "wasi-tokio", @@ -3784,6 +3785,7 @@ dependencies = [ "rand 0.8.5", "wasi-common", "wasmtime", + "wasmtime-wasi", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 86966cb415c2..42d76b246130 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,6 @@ wasmtime-wasi-threads = { workspace = true, optional = true } clap = { workspace = true, features = ["color", "suggestions", "derive"] } anyhow = { workspace = true } target-lexicon = { workspace = true } -libc = "0.2.60" humantime = "2.0.0" once_cell = { workspace = true } listenfd = "1.0.0" @@ -69,6 +68,7 @@ wasmtime-component-util = { workspace = true } component-macro-test = { path = "crates/misc/component-macro-test" } component-test-util = { workspace = true } bstr = "0.2.17" +libc = "0.2.60" [target.'cfg(windows)'.dev-dependencies] windows-sys = { workspace = true, features = ["Win32_System_Memory"] } diff --git a/crates/wasi-threads/Cargo.toml b/crates/wasi-threads/Cargo.toml index 6d212721464c..2667587b83df 100644 --- a/crates/wasi-threads/Cargo.toml +++ b/crates/wasi-threads/Cargo.toml @@ -17,6 +17,7 @@ log = { workspace = true } rand = "0.8" wasi-common = { workspace = true } wasmtime = { workspace = true } +wasmtime-wasi = { workspace = true } [badges] maintenance = { status = "experimental" } diff --git a/crates/wasi-threads/src/lib.rs b/crates/wasi-threads/src/lib.rs index b9a2055b0c61..ebf0ac51788c 100644 --- a/crates/wasi-threads/src/lib.rs +++ b/crates/wasi-threads/src/lib.rs @@ -5,8 +5,8 @@ use anyhow::{anyhow, Result}; use rand::Rng; use std::thread; -use wasi_common::I32Exit; use wasmtime::{Caller, Linker, Module, SharedMemory, Store}; +use wasmtime_wasi::maybe_exit_on_error; // This name is a function export designated by the wasi-threads specification: // https://github.com/WebAssembly/wasi-threads/#detailed-design-discussion @@ -63,15 +63,11 @@ impl WasiThreadsCtx { ); match thread_entry_point.call(&mut store, (wasi_thread_id, thread_start_arg)) { Ok(_) => {} - Err(trap) => { - if let Some(I32Exit(0)) = trap.downcast_ref::() { - log::trace!( - "exited thread id = {} via `wasi::proc_exit` call", - wasi_thread_id - ) - } else { - panic!("{}", fail(trap.to_string())) - } + Err(e) => { + log::trace!("exiting thread id = {} due to error", wasi_thread_id); + let e = maybe_exit_on_error(e); + eprintln!("Error: {:?}", e); + std::process::exit(1); } } })?; diff --git a/crates/wasi/Cargo.toml b/crates/wasi/Cargo.toml index cca14f9597ce..73649f4afabd 100644 --- a/crates/wasi/Cargo.toml +++ b/crates/wasi/Cargo.toml @@ -13,6 +13,7 @@ include = ["src/**/*", "README.md", "LICENSE", "build.rs"] build = "build.rs" [dependencies] +libc = "0.2.60" wasi-common = { workspace = true } wasi-cap-std-sync = { workspace = true, optional = true } wasi-tokio = { workspace = true, optional = true } diff --git a/crates/wasi/src/lib.rs b/crates/wasi/src/lib.rs index a86557769515..6661751017e0 100644 --- a/crates/wasi/src/lib.rs +++ b/crates/wasi/src/lib.rs @@ -82,3 +82,45 @@ pub mod snapshots { } } } + +/// Exit the process with a conventional OS error code as long as Wasmtime +/// understands the error. If the error is not an `I32Exit` or `Trap`, return +/// the error back to the caller for it to decide what to do. +/// +/// Note: this function is designed for CLI usage of Wasmtime; embedders of +/// Wasmtime may want different error handling. +pub fn maybe_exit_on_error(e: anyhow::Error) -> anyhow::Error { + use std::process; + use wasmtime::Trap; + + // If a specific WASI error code was requested then that's + // forwarded through to the process here without printing any + // extra error information. + if let Some(exit) = e.downcast_ref::() { + // Print the error message in the usual way. + // On Windows, exit status 3 indicates an abort (see below), + // so return 1 indicating a non-zero status to avoid ambiguity. + if cfg!(windows) && exit.0 >= 3 { + process::exit(1); + } + process::exit(exit.0); + } + + // If the program exited because of a trap, return an error code + // to the outside environment indicating a more severe problem + // than a simple failure. + if e.is::() { + eprintln!("Error: {:?}", e); + + if cfg!(unix) { + // On Unix, return the error code of an abort. + process::exit(128 + libc::SIGABRT); + } else if cfg!(windows) { + // On Windows, return 3. + // https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/abort?view=vs-2019 + process::exit(3); + } + } + + e +} diff --git a/src/commands/run.rs b/src/commands/run.rs index 5800a8b436d2..4be6a3e8acfc 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -3,18 +3,15 @@ use anyhow::{anyhow, bail, Context as _, Result}; use clap::Parser; use once_cell::sync::Lazy; +use std::ffi::OsStr; +use std::path::{Component, Path, PathBuf}; use std::sync::Arc; use std::thread; use std::time::Duration; -use std::{ - ffi::OsStr, - path::{Component, Path, PathBuf}, - process, -}; -use wasmtime::{Engine, Func, Linker, Module, Store, Trap, Val, ValType}; +use wasmtime::{Engine, Func, Linker, Module, Store, Val, ValType}; use wasmtime_cli_flags::{CommonOptions, WasiModules}; +use wasmtime_wasi::maybe_exit_on_error; use wasmtime_wasi::sync::{ambient_authority, Dir, TcpListener, WasiCtxBuilder}; -use wasmtime_wasi::I32Exit; #[cfg(feature = "wasi-nn")] use wasmtime_wasi_nn::WasiNnCtx; @@ -222,38 +219,10 @@ impl RunCommand { { Ok(()) => (), Err(e) => { - // If a specific WASI error code was requested then that's - // forwarded through to the process here without printing any - // extra error information. - if let Some(exit) = e.downcast_ref::() { - // Print the error message in the usual way. - // On Windows, exit status 3 indicates an abort (see below), - // so return 1 indicating a non-zero status to avoid ambiguity. - if cfg!(windows) && exit.0 >= 3 { - process::exit(1); - } - process::exit(exit.0); - } - - // If the program exited because of a trap, return an error code - // to the outside environment indicating a more severe problem - // than a simple failure. - if e.is::() { - eprintln!("Error: {:?}", e); - - if cfg!(unix) { - // On Unix, return the error code of an abort. - process::exit(128 + libc::SIGABRT); - } else if cfg!(windows) { - // On Windows, return 3. - // https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/abort?view=vs-2019 - process::exit(3); - } - } - - // Otherwise fall back on Rust's default error printing/return + // Exit the process if Wasmtime understands the error; + // otherwise, fall back on Rust's default error printing/return // code. - return Err(e); + return Err(maybe_exit_on_error(e)); } }