Skip to content

Commit

Permalink
Move wasi_proc_exit into the wasmtime-wasi crate.
Browse files Browse the repository at this point in the history
  • Loading branch information
sunfishcode committed May 12, 2020
1 parent 697eb11 commit b4aae4b
Show file tree
Hide file tree
Showing 10 changed files with 43 additions and 124 deletions.
2 changes: 1 addition & 1 deletion crates/api/src/externals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ impl Table {
let src_table = src_table.instance.get_defined_table(src_table_index);

runtime::Table::copy(dst_table, src_table, dst_index, src_index, len)
.map_err(Trap::from_jit)?;
.map_err(Trap::from_runtime)?;
Ok(())
}

Expand Down
44 changes: 2 additions & 42 deletions crates/api/src/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::mem;
use std::panic::{self, AssertUnwindSafe};
use std::ptr;
use std::rc::Weak;
use wasmtime_runtime::{raise_user_trap, wasi_proc_exit, ExportFunction, VMTrampoline};
use wasmtime_runtime::{raise_user_trap, ExportFunction, VMTrampoline};
use wasmtime_runtime::{Export, InstanceHandle, VMContext, VMFunctionBody};

/// A WebAssembly function which can be called.
Expand Down Expand Up @@ -474,46 +474,6 @@ impl Func {
func.into_func(store)
}

/// Creates a new `Func` for a function which performs a program exit,
/// unwinding the stack up the point where wasm was most recently entered.
pub fn exit_func(store: &Store) -> Func {
unsafe extern "C" fn trampoline(
callee_vmctx: *mut VMContext,
caller_vmctx: *mut VMContext,
ptr: *const VMFunctionBody,
args: *mut u128,
) {
let ptr = mem::transmute::<
*const VMFunctionBody,
unsafe extern "C" fn(*mut VMContext, *mut VMContext, i32) -> !,
>(ptr);

let mut next = args as *const u128;
let status = i32::load(&mut next);
ptr(callee_vmctx, caller_vmctx, status)
}

let mut args = Vec::new();
<i32 as WasmTy>::push(&mut args);
let ret = Vec::new();
let ty = FuncType::new(args.into(), ret.into());
let (instance, export) = unsafe {
crate::trampoline::generate_raw_func_export(
&ty,
std::slice::from_raw_parts_mut(wasi_proc_exit as *mut _, 0),
trampoline,
store,
Box::new(()),
)
.expect("failed to generate export")
};
Func {
instance,
export,
trampoline,
}
}

/// Returns the underlying wasm type that this `Func` has.
pub fn ty(&self) -> FuncType {
// Signatures should always be registered in the store's registry of
Expand Down Expand Up @@ -787,7 +747,7 @@ pub(crate) fn catch_traps(
signalhandler.as_deref(),
closure,
)
.map_err(Trap::from_jit)
.map_err(Trap::from_runtime)
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ fn instantiate(
.map_err(|e| -> Error {
match e {
InstantiationError::StartTrap(trap) | InstantiationError::Trap(trap) => {
Trap::from_jit(trap).into()
Trap::from_runtime(trap).into()
}
other => other.into(),
}
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/trampoline/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ unsafe extern "C" fn stub_fn(

// If a trap was raised (an error returned from the imported function)
// then we smuggle the trap through `Box<dyn Error>` through to the
// call-site, which gets unwrapped in `Trap::from_jit` later on as we
// call-site, which gets unwrapped in `Trap::from_runtime` later on as we
// convert from the internal `Trap` type to our own `Trap` type in this
// crate.
Ok(Err(trap)) => wasmtime_runtime::raise_user_trap(Box::new(trap)),
Expand Down
37 changes: 17 additions & 20 deletions crates/api/src/trap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use crate::frame_info::{GlobalFrameInfo, FRAME_INFO};
use crate::FrameInfo;
use backtrace::Backtrace;
use std::fmt;
use std::num::NonZeroI32;
use std::sync::Arc;
use wasmtime_environ::ir::TrapCode;

Expand All @@ -19,15 +18,15 @@ pub enum TrapReason {
/// An error message describing a trap.
Message(String),

/// A non-zero exit status describing an explicit program exit.
Exit(NonZeroI32),
/// An `i32` exit status describing an explicit program exit.
I32Exit(i32),
}

impl fmt::Display for TrapReason {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TrapReason::Message(s) => write!(f, "{}", s),
TrapReason::Exit(status) => write!(f, "Exited with non-zero exit status {}", status),
TrapReason::I32Exit(status) => write!(f, "Exited with i32 exit status {}", status),
}
}
}
Expand All @@ -54,9 +53,21 @@ impl Trap {
Trap::new_with_trace(&info, None, message.into(), Backtrace::new_unresolved())
}

pub(crate) fn from_jit(jit: wasmtime_runtime::Trap) -> Self {
/// Creates a new `Trap` representing an explicit program exit with a classic `i32`
/// exit status value.
pub fn i32_exit(status: i32) -> Self {
Trap {
inner: Arc::new(TrapInner {
reason: TrapReason::I32Exit(status),
wasm_trace: Vec::new(),
native_trace: Backtrace::from(Vec::new()),
}),
}
}

pub(crate) fn from_runtime(runtime_trap: wasmtime_runtime::Trap) -> Self {
let info = FRAME_INFO.read().unwrap();
match jit {
match runtime_trap {
wasmtime_runtime::Trap::User(error) => {
// Since we're the only one using the wasmtime internals (in
// theory) we should only see user errors which were originally
Expand Down Expand Up @@ -91,10 +102,6 @@ impl Trap {
wasmtime_runtime::Trap::OOM { backtrace } => {
Trap::new_with_trace(&info, None, "out of memory".to_string(), backtrace)
}
wasmtime_runtime::Trap::Exit { status } => Trap::new_exit(status),
wasmtime_runtime::Trap::InvalidExitStatus { backtrace } => {
Trap::new_with_trace(&info, None, "invalid exit status".to_string(), backtrace)
}
}
}

Expand Down Expand Up @@ -158,16 +165,6 @@ impl Trap {
}
}

fn new_exit(status: NonZeroI32) -> Self {
Trap {
inner: Arc::new(TrapInner {
reason: TrapReason::Exit(status),
wasm_trace: Vec::new(),
native_trace: Backtrace::from(Vec::new()),
}),
}
}

/// Returns a reference the `message` stored in `Trap`.
pub fn reason(&self) -> &TrapReason {
&self.inner.reason
Expand Down
3 changes: 1 addition & 2 deletions crates/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ pub use crate::mmap::Mmap;
pub use crate::sig_registry::SignatureRegistry;
pub use crate::table::Table;
pub use crate::traphandlers::{
catch_traps, init_traps, raise_lib_trap, raise_user_trap, resume_panic, wasi_proc_exit,
SignalHandler, Trap,
catch_traps, init_traps, raise_lib_trap, raise_user_trap, resume_panic, SignalHandler, Trap,
};
pub use crate::vmcontext::{
VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, VMFunctionImport, VMGlobalDefinition,
Expand Down
53 changes: 0 additions & 53 deletions crates/runtime/src/traphandlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use std::any::Any;
use std::cell::Cell;
use std::error::Error;
use std::io;
use std::num::NonZeroI32;
use std::ptr;
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use std::sync::Once;
Expand Down Expand Up @@ -340,18 +339,6 @@ pub enum Trap {
/// Native stack backtrace at the time the OOM occurred
backtrace: Backtrace,
},

/// A program exit was requested with a non-zero exit status.
Exit {
/// The exit status
status: NonZeroI32,
},

/// A program exit was requested with an invalid exit status.
InvalidExitStatus {
/// Native stack backtrace at the time the error occurred
backtrace: Backtrace,
},
}

impl Trap {
Expand All @@ -373,14 +360,6 @@ impl Trap {
let backtrace = Backtrace::new_unresolved();
Trap::OOM { backtrace }
}

/// Construct a new InvalidExitStatus trap with the given source location.
///
/// Internally saves a backtrace when constructed.
pub fn invalid_exit_status() -> Self {
let backtrace = Backtrace::new_unresolved();
Trap::InvalidExitStatus { backtrace }
}
}

/// Catches any wasm traps that happen within the execution of `closure`,
Expand Down Expand Up @@ -434,7 +413,6 @@ enum UnwindReason {
UserTrap(Box<dyn Error + Send + Sync>),
LibTrap(Trap),
JitTrap { backtrace: Backtrace, pc: usize },
Exit { status: i32 },
}

impl<'a> CallThreadState<'a> {
Expand Down Expand Up @@ -482,13 +460,6 @@ impl<'a> CallThreadState<'a> {
maybe_interrupted,
})
}
UnwindReason::Exit { status } => {
if let Some(status) = NonZeroI32::new(status) {
Err(Trap::Exit { status })
} else {
Ok(())
}
}
UnwindReason::Panic(panic) => {
debug_assert_eq!(ret, 0);
std::panic::resume_unwind(panic)
Expand Down Expand Up @@ -815,27 +786,3 @@ fn setup_unix_sigaltstack() -> Result<(), Trap> {
}
}
}

/// Perform a program exit by unwinding the stack to the point where wasm
/// as most recently entered, carrying an exit status value.
///
/// This is implemented in `wasmtime_runtime` rather than with the rest of the WASI
/// functions as it's essentially an unwinding operation.
///
/// # Safety
///
/// Only safe to call when wasm code is on the stack, aka `catch_traps` must
/// have been previously called. Additionally no Rust destructors can be on the
/// stack. They will be skipped and not executed.
pub unsafe extern "C" fn wasi_proc_exit(
_vmctx: *mut VMContext,
_caller_vmctx: *mut VMContext,
status: i32,
) -> ! {
// Check that the status is within WASI's range.
if status >= 0 && status < 126 {
tls::with(|info| info.unwrap().unwind_with(UnwindReason::Exit { status }))
} else {
raise_lib_trap(Trap::invalid_exit_status())
}
}
4 changes: 2 additions & 2 deletions crates/wasi-common/wig/src/wasi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub fn define_struct(args: TokenStream) -> TokenStream {
// in wasi-common.
if name == "proc_exit" {
ctor_externs.push(quote! {
let #name_ident = wasmtime::Func::exit_func(store);
let #name_ident = wasmtime::Func::wrap(store, crate::wasi_proc_exit);
});
continue;
}
Expand Down Expand Up @@ -305,7 +305,7 @@ pub fn define_struct_for_wiggle(args: TokenStream) -> TokenStream {
// in wasi-common.
if name == "proc_exit" {
ctor_externs.push(quote! {
let #name_ident = wasmtime::Func::exit_func(store);
let #name_ident = wasmtime::Func::wrap(store, crate::wasi_proc_exit);
});
continue;
}
Expand Down
16 changes: 16 additions & 0 deletions crates/wasi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use wasmtime::Trap;

pub mod old;

pub use wasi_common::{WasiCtx, WasiCtxBuilder};
Expand All @@ -12,3 +14,17 @@ pub fn is_wasi_module(name: &str) -> bool {
// trick.
name.starts_with("wasi")
}

/// Implement the WASI `proc_exit` function. This function is implemented here
/// instead of in wasi-common so that we can use the runtime to perform an
/// unwind rather than exiting the host process.
fn wasi_proc_exit(status: i32) -> Result<(), Trap> {
// Check that the status is within WASI's range.
if status >= 0 && status < 126 {
Err(Trap::i32_exit(status))
} else {
Err(Trap::new(
"exit with invalid exit status outside of [0..126)",
))
}
}
4 changes: 2 additions & 2 deletions src/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,13 @@ impl RunCommand {
// Print the error message in the usual way.
eprintln!("Error: {:?}", e);

if let TrapReason::Exit(status) = trap.reason() {
if let TrapReason::I32Exit(status) = trap.reason() {
// On Windows, exit status 3 indicates an abort (see below),
// so just return 1 indicating a non-zero status.
if cfg!(windows) {
process::exit(1);
}
process::exit(status.get());
process::exit(*status);
}

// If the program exited because of a trap, return an error code
Expand Down

0 comments on commit b4aae4b

Please sign in to comment.