Skip to content

Commit b4aae4b

Browse files
committed
Move wasi_proc_exit into the wasmtime-wasi crate.
1 parent 697eb11 commit b4aae4b

File tree

10 files changed

+43
-124
lines changed

10 files changed

+43
-124
lines changed

crates/api/src/externals.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ impl Table {
420420
let src_table = src_table.instance.get_defined_table(src_table_index);
421421

422422
runtime::Table::copy(dst_table, src_table, dst_index, src_index, len)
423-
.map_err(Trap::from_jit)?;
423+
.map_err(Trap::from_runtime)?;
424424
Ok(())
425425
}
426426

crates/api/src/func.rs

Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::mem;
88
use std::panic::{self, AssertUnwindSafe};
99
use std::ptr;
1010
use std::rc::Weak;
11-
use wasmtime_runtime::{raise_user_trap, wasi_proc_exit, ExportFunction, VMTrampoline};
11+
use wasmtime_runtime::{raise_user_trap, ExportFunction, VMTrampoline};
1212
use wasmtime_runtime::{Export, InstanceHandle, VMContext, VMFunctionBody};
1313

1414
/// A WebAssembly function which can be called.
@@ -474,46 +474,6 @@ impl Func {
474474
func.into_func(store)
475475
}
476476

477-
/// Creates a new `Func` for a function which performs a program exit,
478-
/// unwinding the stack up the point where wasm was most recently entered.
479-
pub fn exit_func(store: &Store) -> Func {
480-
unsafe extern "C" fn trampoline(
481-
callee_vmctx: *mut VMContext,
482-
caller_vmctx: *mut VMContext,
483-
ptr: *const VMFunctionBody,
484-
args: *mut u128,
485-
) {
486-
let ptr = mem::transmute::<
487-
*const VMFunctionBody,
488-
unsafe extern "C" fn(*mut VMContext, *mut VMContext, i32) -> !,
489-
>(ptr);
490-
491-
let mut next = args as *const u128;
492-
let status = i32::load(&mut next);
493-
ptr(callee_vmctx, caller_vmctx, status)
494-
}
495-
496-
let mut args = Vec::new();
497-
<i32 as WasmTy>::push(&mut args);
498-
let ret = Vec::new();
499-
let ty = FuncType::new(args.into(), ret.into());
500-
let (instance, export) = unsafe {
501-
crate::trampoline::generate_raw_func_export(
502-
&ty,
503-
std::slice::from_raw_parts_mut(wasi_proc_exit as *mut _, 0),
504-
trampoline,
505-
store,
506-
Box::new(()),
507-
)
508-
.expect("failed to generate export")
509-
};
510-
Func {
511-
instance,
512-
export,
513-
trampoline,
514-
}
515-
}
516-
517477
/// Returns the underlying wasm type that this `Func` has.
518478
pub fn ty(&self) -> FuncType {
519479
// Signatures should always be registered in the store's registry of
@@ -787,7 +747,7 @@ pub(crate) fn catch_traps(
787747
signalhandler.as_deref(),
788748
closure,
789749
)
790-
.map_err(Trap::from_jit)
750+
.map_err(Trap::from_runtime)
791751
}
792752
}
793753

crates/api/src/instance.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ fn instantiate(
5252
.map_err(|e| -> Error {
5353
match e {
5454
InstantiationError::StartTrap(trap) | InstantiationError::Trap(trap) => {
55-
Trap::from_jit(trap).into()
55+
Trap::from_runtime(trap).into()
5656
}
5757
other => other.into(),
5858
}

crates/api/src/trampoline/func.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ unsafe extern "C" fn stub_fn(
5454

5555
// If a trap was raised (an error returned from the imported function)
5656
// then we smuggle the trap through `Box<dyn Error>` through to the
57-
// call-site, which gets unwrapped in `Trap::from_jit` later on as we
57+
// call-site, which gets unwrapped in `Trap::from_runtime` later on as we
5858
// convert from the internal `Trap` type to our own `Trap` type in this
5959
// crate.
6060
Ok(Err(trap)) => wasmtime_runtime::raise_user_trap(Box::new(trap)),

crates/api/src/trap.rs

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use crate::frame_info::{GlobalFrameInfo, FRAME_INFO};
22
use crate::FrameInfo;
33
use backtrace::Backtrace;
44
use std::fmt;
5-
use std::num::NonZeroI32;
65
use std::sync::Arc;
76
use wasmtime_environ::ir::TrapCode;
87

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

22-
/// A non-zero exit status describing an explicit program exit.
23-
Exit(NonZeroI32),
21+
/// An `i32` exit status describing an explicit program exit.
22+
I32Exit(i32),
2423
}
2524

2625
impl fmt::Display for TrapReason {
2726
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2827
match self {
2928
TrapReason::Message(s) => write!(f, "{}", s),
30-
TrapReason::Exit(status) => write!(f, "Exited with non-zero exit status {}", status),
29+
TrapReason::I32Exit(status) => write!(f, "Exited with i32 exit status {}", status),
3130
}
3231
}
3332
}
@@ -54,9 +53,21 @@ impl Trap {
5453
Trap::new_with_trace(&info, None, message.into(), Backtrace::new_unresolved())
5554
}
5655

57-
pub(crate) fn from_jit(jit: wasmtime_runtime::Trap) -> Self {
56+
/// Creates a new `Trap` representing an explicit program exit with a classic `i32`
57+
/// exit status value.
58+
pub fn i32_exit(status: i32) -> Self {
59+
Trap {
60+
inner: Arc::new(TrapInner {
61+
reason: TrapReason::I32Exit(status),
62+
wasm_trace: Vec::new(),
63+
native_trace: Backtrace::from(Vec::new()),
64+
}),
65+
}
66+
}
67+
68+
pub(crate) fn from_runtime(runtime_trap: wasmtime_runtime::Trap) -> Self {
5869
let info = FRAME_INFO.read().unwrap();
59-
match jit {
70+
match runtime_trap {
6071
wasmtime_runtime::Trap::User(error) => {
6172
// Since we're the only one using the wasmtime internals (in
6273
// theory) we should only see user errors which were originally
@@ -91,10 +102,6 @@ impl Trap {
91102
wasmtime_runtime::Trap::OOM { backtrace } => {
92103
Trap::new_with_trace(&info, None, "out of memory".to_string(), backtrace)
93104
}
94-
wasmtime_runtime::Trap::Exit { status } => Trap::new_exit(status),
95-
wasmtime_runtime::Trap::InvalidExitStatus { backtrace } => {
96-
Trap::new_with_trace(&info, None, "invalid exit status".to_string(), backtrace)
97-
}
98105
}
99106
}
100107

@@ -158,16 +165,6 @@ impl Trap {
158165
}
159166
}
160167

161-
fn new_exit(status: NonZeroI32) -> Self {
162-
Trap {
163-
inner: Arc::new(TrapInner {
164-
reason: TrapReason::Exit(status),
165-
wasm_trace: Vec::new(),
166-
native_trace: Backtrace::from(Vec::new()),
167-
}),
168-
}
169-
}
170-
171168
/// Returns a reference the `message` stored in `Trap`.
172169
pub fn reason(&self) -> &TrapReason {
173170
&self.inner.reason

crates/runtime/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@ pub use crate::mmap::Mmap;
4444
pub use crate::sig_registry::SignatureRegistry;
4545
pub use crate::table::Table;
4646
pub use crate::traphandlers::{
47-
catch_traps, init_traps, raise_lib_trap, raise_user_trap, resume_panic, wasi_proc_exit,
48-
SignalHandler, Trap,
47+
catch_traps, init_traps, raise_lib_trap, raise_user_trap, resume_panic, SignalHandler, Trap,
4948
};
5049
pub use crate::vmcontext::{
5150
VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, VMFunctionImport, VMGlobalDefinition,

crates/runtime/src/traphandlers.rs

Lines changed: 0 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use std::any::Any;
77
use std::cell::Cell;
88
use std::error::Error;
99
use std::io;
10-
use std::num::NonZeroI32;
1110
use std::ptr;
1211
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
1312
use std::sync::Once;
@@ -340,18 +339,6 @@ pub enum Trap {
340339
/// Native stack backtrace at the time the OOM occurred
341340
backtrace: Backtrace,
342341
},
343-
344-
/// A program exit was requested with a non-zero exit status.
345-
Exit {
346-
/// The exit status
347-
status: NonZeroI32,
348-
},
349-
350-
/// A program exit was requested with an invalid exit status.
351-
InvalidExitStatus {
352-
/// Native stack backtrace at the time the error occurred
353-
backtrace: Backtrace,
354-
},
355342
}
356343

357344
impl Trap {
@@ -373,14 +360,6 @@ impl Trap {
373360
let backtrace = Backtrace::new_unresolved();
374361
Trap::OOM { backtrace }
375362
}
376-
377-
/// Construct a new InvalidExitStatus trap with the given source location.
378-
///
379-
/// Internally saves a backtrace when constructed.
380-
pub fn invalid_exit_status() -> Self {
381-
let backtrace = Backtrace::new_unresolved();
382-
Trap::InvalidExitStatus { backtrace }
383-
}
384363
}
385364

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

440418
impl<'a> CallThreadState<'a> {
@@ -482,13 +460,6 @@ impl<'a> CallThreadState<'a> {
482460
maybe_interrupted,
483461
})
484462
}
485-
UnwindReason::Exit { status } => {
486-
if let Some(status) = NonZeroI32::new(status) {
487-
Err(Trap::Exit { status })
488-
} else {
489-
Ok(())
490-
}
491-
}
492463
UnwindReason::Panic(panic) => {
493464
debug_assert_eq!(ret, 0);
494465
std::panic::resume_unwind(panic)
@@ -815,27 +786,3 @@ fn setup_unix_sigaltstack() -> Result<(), Trap> {
815786
}
816787
}
817788
}
818-
819-
/// Perform a program exit by unwinding the stack to the point where wasm
820-
/// as most recently entered, carrying an exit status value.
821-
///
822-
/// This is implemented in `wasmtime_runtime` rather than with the rest of the WASI
823-
/// functions as it's essentially an unwinding operation.
824-
///
825-
/// # Safety
826-
///
827-
/// Only safe to call when wasm code is on the stack, aka `catch_traps` must
828-
/// have been previously called. Additionally no Rust destructors can be on the
829-
/// stack. They will be skipped and not executed.
830-
pub unsafe extern "C" fn wasi_proc_exit(
831-
_vmctx: *mut VMContext,
832-
_caller_vmctx: *mut VMContext,
833-
status: i32,
834-
) -> ! {
835-
// Check that the status is within WASI's range.
836-
if status >= 0 && status < 126 {
837-
tls::with(|info| info.unwrap().unwind_with(UnwindReason::Exit { status }))
838-
} else {
839-
raise_lib_trap(Trap::invalid_exit_status())
840-
}
841-
}

crates/wasi-common/wig/src/wasi.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub fn define_struct(args: TokenStream) -> TokenStream {
5151
// in wasi-common.
5252
if name == "proc_exit" {
5353
ctor_externs.push(quote! {
54-
let #name_ident = wasmtime::Func::exit_func(store);
54+
let #name_ident = wasmtime::Func::wrap(store, crate::wasi_proc_exit);
5555
});
5656
continue;
5757
}
@@ -305,7 +305,7 @@ pub fn define_struct_for_wiggle(args: TokenStream) -> TokenStream {
305305
// in wasi-common.
306306
if name == "proc_exit" {
307307
ctor_externs.push(quote! {
308-
let #name_ident = wasmtime::Func::exit_func(store);
308+
let #name_ident = wasmtime::Func::wrap(store, crate::wasi_proc_exit);
309309
});
310310
continue;
311311
}

crates/wasi/src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use wasmtime::Trap;
2+
13
pub mod old;
24

35
pub use wasi_common::{WasiCtx, WasiCtxBuilder};
@@ -12,3 +14,17 @@ pub fn is_wasi_module(name: &str) -> bool {
1214
// trick.
1315
name.starts_with("wasi")
1416
}
17+
18+
/// Implement the WASI `proc_exit` function. This function is implemented here
19+
/// instead of in wasi-common so that we can use the runtime to perform an
20+
/// unwind rather than exiting the host process.
21+
fn wasi_proc_exit(status: i32) -> Result<(), Trap> {
22+
// Check that the status is within WASI's range.
23+
if status >= 0 && status < 126 {
24+
Err(Trap::i32_exit(status))
25+
} else {
26+
Err(Trap::new(
27+
"exit with invalid exit status outside of [0..126)",
28+
))
29+
}
30+
}

src/commands/run.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,13 @@ impl RunCommand {
148148
// Print the error message in the usual way.
149149
eprintln!("Error: {:?}", e);
150150

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

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

0 commit comments

Comments
 (0)