diff --git a/RELEASES.md b/RELEASES.md index 7dda49ed5a7e..1420b3ce2cea 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -2,6 +2,29 @@ -------------------------------------------------------------------------------- +## 0.16.0 + +Unreleased + +### Added + +* The C API has a number of new `wasmtime_*` functions which return error + objects to get detailed error information when an API fails. + [#TODO](https://github.com/bytecodealliance/wasmtime/pull/TODO) + +### Changed + +* The `Func::call` API has changed its error type from `Trap` to `anyhow::Error` + to distinguish between wasm traps and runtiem violations (like the wrong + number of parameters). + [#TODO](https://github.com/bytecodealliance/wasmtime/pull/TODO) + +* A number of `wasmtime_linker_*` and `wasmtime_config_*` C APIs have new type + signatures which reflect returning errors. + [#TODO](https://github.com/bytecodealliance/wasmtime/pull/TODO) + +-------------------------------------------------------------------------------- + ## 0.15.0 Unreleased diff --git a/crates/api/src/func.rs b/crates/api/src/func.rs index e596caf46dbc..24ff6f9c43dd 100644 --- a/crates/api/src/func.rs +++ b/crates/api/src/func.rs @@ -1,5 +1,5 @@ use crate::{Extern, FuncType, Memory, Store, Trap, Val, ValType}; -use anyhow::{ensure, Context as _}; +use anyhow::{bail, ensure, Context as _, Result}; use std::cmp::max; use std::fmt; use std::mem; @@ -493,18 +493,18 @@ impl Func { /// /// This function should not panic unless the underlying function itself /// initiates a panic. - pub fn call(&self, params: &[Val]) -> Result, Trap> { + pub fn call(&self, params: &[Val]) -> Result> { // We need to perform a dynamic check that the arguments given to us // match the signature of this function and are appropriate to pass to // this function. This involves checking to make sure we have the right // number and types of arguments as well as making sure everything is // from the same `Store`. if self.ty.params().len() != params.len() { - return Err(Trap::new(format!( + bail!( "expected {} arguments, got {}", self.ty.params().len(), params.len() - ))); + ); } let mut values_vec = vec![0; max(params.len(), self.ty.results().len())]; @@ -513,12 +513,10 @@ impl Func { let param_tys = self.ty.params().iter(); for ((arg, slot), ty) in params.iter().zip(&mut values_vec).zip(param_tys) { if arg.ty() != *ty { - return Err(Trap::new("argument type mismatch")); + bail!("argument type mismatch"); } if !arg.comes_from_same_store(&self.store) { - return Err(Trap::new( - "cross-`Store` values are not currently supported", - )); + bail!("cross-`Store` values are not currently supported"); } unsafe { arg.write_value_to(slot); @@ -536,7 +534,7 @@ impl Func { ) }) } { - return Err(Trap::from_jit(error)); + return Err(Trap::from_jit(error).into()); } // Load the return values out of `values_vec`. diff --git a/crates/api/tests/func.rs b/crates/api/tests/func.rs index be2cd15e7a0a..431de864536e 100644 --- a/crates/api/tests/func.rs +++ b/crates/api/tests/func.rs @@ -174,11 +174,12 @@ fn import_works() -> Result<()> { } #[test] -fn trap_smoke() { +fn trap_smoke() -> Result<()> { let store = Store::default(); let f = Func::wrap(&store, || -> Result<(), Trap> { Err(Trap::new("test")) }); - let err = f.call(&[]).unwrap_err(); + let err = f.call(&[]).unwrap_err().downcast::()?; assert_eq!(err.message(), "test"); + Ok(()) } #[test] @@ -391,7 +392,7 @@ fn func_write_nothing() -> anyhow::Result<()> { let store = Store::default(); let ty = FuncType::new(Box::new([]), Box::new([ValType::I32])); let f = Func::new(&store, ty, |_, _, _| Ok(())); - let err = f.call(&[]).unwrap_err(); + let err = f.call(&[]).unwrap_err().downcast::()?; assert_eq!( err.message(), "function attempted to return an incompatible value" diff --git a/crates/api/tests/import_calling_export.rs b/crates/api/tests/import_calling_export.rs index 6281d4830c43..44db6f39f374 100644 --- a/crates/api/tests/import_calling_export.rs +++ b/crates/api/tests/import_calling_export.rs @@ -1,3 +1,4 @@ +use anyhow::Result; use std::cell::RefCell; use std::rc::Rc; use wasmtime::*; @@ -57,7 +58,7 @@ fn test_import_calling_export() { } #[test] -fn test_returns_incorrect_type() { +fn test_returns_incorrect_type() -> Result<()> { const WAT: &str = r#" (module (import "env" "evil" (func $evil (result i32))) @@ -68,7 +69,7 @@ fn test_returns_incorrect_type() { "#; let store = Store::default(); - let module = Module::new(&store, WAT).expect("failed to create module"); + let module = Module::new(&store, WAT)?; let callback_func = Func::new( &store, @@ -81,8 +82,7 @@ fn test_returns_incorrect_type() { ); let imports = vec![callback_func.into()]; - let instance = - Instance::new(&module, imports.as_slice()).expect("failed to instantiate module"); + let instance = Instance::new(&module, imports.as_slice())?; let exports = instance.exports(); assert!(!exports.is_empty()); @@ -91,9 +91,13 @@ fn test_returns_incorrect_type() { .func() .expect("expected a run func in the module"); - let trap = run_func.call(&[]).expect_err("the execution should fail"); + let trap = run_func + .call(&[]) + .expect_err("the execution should fail") + .downcast::()?; assert_eq!( trap.message(), "function attempted to return an incompatible value" ); + Ok(()) } diff --git a/crates/api/tests/traps.rs b/crates/api/tests/traps.rs index b403ae51f249..e76f6a3dcd80 100644 --- a/crates/api/tests/traps.rs +++ b/crates/api/tests/traps.rs @@ -21,7 +21,11 @@ fn test_trap_return() -> Result<()> { .func() .expect("expected function export"); - let e = run_func.call(&[]).err().expect("error calling function"); + let e = run_func + .call(&[]) + .err() + .expect("error calling function") + .downcast::()?; assert_eq!(e.message(), "test 123"); @@ -44,7 +48,11 @@ fn test_trap_trace() -> Result<()> { .func() .expect("expected function export"); - let e = run_func.call(&[]).err().expect("error calling function"); + let e = run_func + .call(&[]) + .err() + .expect("error calling function") + .downcast::()?; let trace = e.trace(); assert_eq!(trace.len(), 2); @@ -83,7 +91,11 @@ fn test_trap_trace_cb() -> Result<()> { .func() .expect("expected function export"); - let e = run_func.call(&[]).err().expect("error calling function"); + let e = run_func + .call(&[]) + .err() + .expect("error calling function") + .downcast::()?; let trace = e.trace(); assert_eq!(trace.len(), 2); @@ -111,7 +123,11 @@ fn test_trap_stack_overflow() -> Result<()> { .func() .expect("expected function export"); - let e = run_func.call(&[]).err().expect("error calling function"); + let e = run_func + .call(&[]) + .err() + .expect("error calling function") + .downcast::()?; let trace = e.trace(); assert!(trace.len() >= 32); @@ -315,17 +331,17 @@ fn mismatched_arguments() -> Result<()> { let instance = Instance::new(&module, &[])?; let func = instance.exports()[0].func().unwrap().clone(); assert_eq!( - func.call(&[]).unwrap_err().message(), + func.call(&[]).unwrap_err().to_string(), "expected 1 arguments, got 0" ); assert_eq!( - func.call(&[Val::F32(0)]).unwrap_err().message(), + func.call(&[Val::F32(0)]).unwrap_err().to_string(), "argument type mismatch", ); assert_eq!( func.call(&[Val::I32(0), Val::I32(1)]) .unwrap_err() - .message(), + .to_string(), "expected 1 arguments, got 2" ); Ok(()) diff --git a/crates/c-api/include/wasmtime.h b/crates/c-api/include/wasmtime.h index 997606dd2839..f8cf4ed6f223 100644 --- a/crates/c-api/include/wasmtime.h +++ b/crates/c-api/include/wasmtime.h @@ -12,6 +12,18 @@ extern "C" { #define own +#define WASMTIME_DECLARE_OWN(name) \ + typedef struct wasmtime_##name##_t wasmtime_##name##_t; \ + \ + WASM_API_EXTERN void wasmtime_##name##_delete(own wasmtime_##name##_t*); + +WASMTIME_DECLARE_OWN(error) + +WASM_API_EXTERN void wasmtime_error_message( + const wasmtime_error_t *error, + own wasm_name_t *message +); + typedef uint8_t wasmtime_strategy_t; enum wasmtime_strategy_enum { // Strategy WASMTIME_STRATEGY_AUTO, @@ -42,10 +54,10 @@ WASMTIME_CONFIG_PROP(void, wasm_reference_types, bool) WASMTIME_CONFIG_PROP(void, wasm_simd, bool) WASMTIME_CONFIG_PROP(void, wasm_bulk_memory, bool) WASMTIME_CONFIG_PROP(void, wasm_multi_value, bool) -WASMTIME_CONFIG_PROP(bool, strategy, wasmtime_strategy_t) +WASMTIME_CONFIG_PROP(wasmtime_error_t*, strategy, wasmtime_strategy_t) WASMTIME_CONFIG_PROP(void, cranelift_debug_verifier, bool) WASMTIME_CONFIG_PROP(void, cranelift_opt_level, wasmtime_opt_level_t) -WASMTIME_CONFIG_PROP(bool, profiler, wasmtime_profiling_strategy_t) +WASMTIME_CONFIG_PROP(wasmtime_error_t*, profiler, wasmtime_profiling_strategy_t) /////////////////////////////////////////////////////////////////////////////// @@ -55,53 +67,46 @@ WASMTIME_CONFIG_PROP(bool, profiler, wasmtime_profiling_strategy_t) // it. This will be parsed and converted to the binary format. // * `ret` - if the conversion is successful, this byte vector is filled in with // the WebAssembly binary format. -// * `error_message` - if the conversion fails, this is filled in with a -// descriptive error message of why parsing failed. This parameter is -// optional. // -// Returns `true` if conversion succeeded, or `false` if it failed. -WASM_API_EXTERN bool wasmtime_wat2wasm( +// Returns a non-null error if parsing fails, or returns `NULL`. If parsing +// fails then `ret` isn't touched. +WASM_API_EXTERN own wasmtime_error_t* wasmtime_wat2wasm( const wasm_byte_vec_t *wat, - own wasm_byte_vec_t *ret, - own wasm_byte_vec_t *error_message + own wasm_byte_vec_t *ret ); /////////////////////////////////////////////////////////////////////////////// // // wasmtime_linker_t extension type, binding the `Linker` type in the Rust API -#define WASMTIME_DECLARE_OWN(name) \ - typedef struct wasmtime_##name##_t wasmtime_##name##_t; \ - \ - WASM_API_EXTERN void wasmtime_##name##_delete(own wasmtime_##name##_t*); - WASMTIME_DECLARE_OWN(linker) WASM_API_EXTERN own wasmtime_linker_t* wasmtime_linker_new(wasm_store_t* store); WASM_API_EXTERN void wasmtime_linker_allow_shadowing(wasmtime_linker_t* linker, bool allow_shadowing); -WASM_API_EXTERN bool wasmtime_linker_define( +WASM_API_EXTERN own wasmtime_error_t* wasmtime_linker_define( wasmtime_linker_t *linker, const wasm_name_t *module, const wasm_name_t *name, const wasm_extern_t *item ); -WASM_API_EXTERN bool wasmtime_linker_define_wasi( +WASM_API_EXTERN own wasmtime_error_t* wasmtime_linker_define_wasi( wasmtime_linker_t *linker, const wasi_instance_t *instance ); -WASM_API_EXTERN bool wasmtime_linker_define_instance( +WASM_API_EXTERN own wasmtime_error_t* wasmtime_linker_define_instance( wasmtime_linker_t *linker, const wasm_name_t *name, const wasm_instance_t *instance ); -WASM_API_EXTERN wasm_instance_t* wasmtime_linker_instantiate( +WASM_API_EXTERN own wasmtime_error_t* wasmtime_linker_instantiate( const wasmtime_linker_t *linker, const wasm_module_t *module, + own wasm_instance_t **instance, own wasm_trap_t **trap ); @@ -133,6 +138,98 @@ WASM_API_EXTERN own wasm_extern_t* wasmtime_caller_export_get(const wasmtime_cal WASM_API_EXTERN const wasm_name_t *wasmtime_frame_func_name(const wasm_frame_t*); WASM_API_EXTERN const wasm_name_t *wasmtime_frame_module_name(const wasm_frame_t*); +/////////////////////////////////////////////////////////////////////////////// +// +// Extensions to the C API which augment existing functionality with extra +// error reporting, safety, etc. + +// Similar to `wasm_func_call`, but with a few tweaks: +// +// * `args` and `results` have a size parameter saying how big the arrays are +// * An error *and* a trap can be returned +// * Errors are returned if `args` have the wrong types, if the args/results +// arrays have the wrong lengths, or if values come from the wrong store. +// +// The are three possible return states from this function: +// +// 1. The returned error is non-null. This means `results` +// wasn't written to and `trap` will have `NULL` written to it. This state +// means that programmer error happened when calling the function (e.g. the +// size of the args/results were wrong) +// 2. The trap pointer is filled in. This means the returned error is `NULL` and +// `results` was not written to. This state means that the function was +// executing but hit a wasm trap while executing. +// 3. The error and trap returned are both `NULL` and `results` are written to. +// This means that the function call worked and the specified results were +// produced. +// +// The `trap` pointer cannot be `NULL`. The `args` and `results` pointers may be +// `NULL` if the corresponding length is zero. +WASM_API_EXTERN own wasmtime_error_t *wasmtime_func_call( + wasm_func_t *func, + const wasm_val_t *args, + size_t num_args, + wasm_val_t *results, + size_t num_results, + own wasm_trap_t **trap +); + +// Similar to `wasm_global_new`, but with a few tweaks: +// +// * An error is returned instead of `wasm_global_t`, which is taken as an +// out-parameter +// * An error happens when the `type` specified does not match the type of the +// value `val`, or if it comes from a different store than `store`. +WASM_API_EXTERN own wasmtime_error_t *wasmtime_global_new( + wasm_store_t *store, + const wasm_globaltype_t *type, + const wasm_val_t *val, + own wasm_global_t **ret +); + +// Similar to `wasm_global_set`, but with an error that can be returned if the +// specified value does not come from the same store as this global, if the +// global is immutable, or if the specified value has the wrong type. +WASM_API_EXTERN own wasmtime_error_t *wasmtime_global_set( + wasm_global_t *global, + const wasm_val_t *val +); + +// Similar to `wasm_instance_new`, but with tweaks: +// +// * An error message can be returned from this function. +// * The number of imports specified is passed as an argument +// * The `trap` pointer is required to not be NULL. +// * No `wasm_store_t` argument is required. +// +// The states of return values from this function are similar to +// `wasmtime_func_call` where an error can be returned meaning something like a +// link error in this context. A trap can be returned (meaning no error or +// instance is returned), or an instance can be returned (meaning no error or +// trap is returned). +WASM_API_EXTERN own wasmtime_error_t *wasmtime_instance_new( + const wasm_module_t *module, + const wasm_extern_t* const imports[], + size_t num_imports, + own wasm_instance_t **instance, + own wasm_trap_t **trap +); + +// Similar to `wasm_module_new`, but an error is returned to return a +// descriptive error message in case compilation fails. +WASM_API_EXTERN own wasmtime_error_t *wasmtime_module_new( + wasm_store_t *store, + const wasm_byte_vec_t *binary, + own wasm_module_t **ret +); + +// Similar to `wasm_module_validate`, but an error is returned to return a +// descriptive error message in case compilation fails. +WASM_API_EXTERN own wasmtime_error_t *wasmtime_module_validate( + wasm_store_t *store, + const wasm_byte_vec_t *binary +); + #undef own #ifdef __cplusplus diff --git a/crates/c-api/src/config.rs b/crates/c-api/src/config.rs index 7e4cebcf88a1..5a93fdcfb4e9 100644 --- a/crates/c-api/src/config.rs +++ b/crates/c-api/src/config.rs @@ -1,3 +1,4 @@ +use crate::{handle_result, wasmtime_error_t}; use wasmtime::{Config, OptLevel, ProfilingStrategy, Strategy}; #[repr(C)] @@ -72,15 +73,14 @@ pub extern "C" fn wasmtime_config_wasm_multi_value_set(c: &mut wasm_config_t, en pub extern "C" fn wasmtime_config_strategy_set( c: &mut wasm_config_t, strategy: wasmtime_strategy_t, -) -> bool { +) -> Option> { use wasmtime_strategy_t::*; - c.config - .strategy(match strategy { - WASMTIME_STRATEGY_AUTO => Strategy::Auto, - WASMTIME_STRATEGY_CRANELIFT => Strategy::Cranelift, - WASMTIME_STRATEGY_LIGHTBEAM => Strategy::Lightbeam, - }) - .is_ok() + let result = c.config.strategy(match strategy { + WASMTIME_STRATEGY_AUTO => Strategy::Auto, + WASMTIME_STRATEGY_CRANELIFT => Strategy::Cranelift, + WASMTIME_STRATEGY_LIGHTBEAM => Strategy::Lightbeam, + }); + handle_result(result, |_cfg| {}) } #[no_mangle] @@ -108,12 +108,11 @@ pub extern "C" fn wasmtime_config_cranelift_opt_level_set( pub extern "C" fn wasmtime_config_profiler_set( c: &mut wasm_config_t, strategy: wasmtime_profiling_strategy_t, -) -> bool { +) -> Option> { use wasmtime_profiling_strategy_t::*; - c.config - .profiler(match strategy { - WASMTIME_PROFILING_STRATEGY_NONE => ProfilingStrategy::None, - WASMTIME_PROFILING_STRATEGY_JITDUMP => ProfilingStrategy::JitDump, - }) - .is_ok() + let result = c.config.profiler(match strategy { + WASMTIME_PROFILING_STRATEGY_NONE => ProfilingStrategy::None, + WASMTIME_PROFILING_STRATEGY_JITDUMP => ProfilingStrategy::JitDump, + }); + handle_result(result, |_cfg| {}) } diff --git a/crates/c-api/src/error.rs b/crates/c-api/src/error.rs new file mode 100644 index 000000000000..db0e25eae1ee --- /dev/null +++ b/crates/c-api/src/error.rs @@ -0,0 +1,46 @@ +use crate::{wasm_name_t, wasm_trap_t}; +use anyhow::{anyhow, Error, Result}; +use wasmtime::Trap; + +#[repr(C)] +pub struct wasmtime_error_t { + error: Error, +} + +wasmtime_c_api_macros::declare_own!(wasmtime_error_t); + +impl wasmtime_error_t { + pub(crate) fn to_trap(&self) -> Box { + Box::new(wasm_trap_t::new(Trap::new(format!("{:?}", self.error)))) + } +} + +impl From for wasmtime_error_t { + fn from(error: Error) -> wasmtime_error_t { + wasmtime_error_t { error } + } +} + +pub(crate) fn handle_result( + result: Result, + ok: impl FnOnce(T), +) -> Option> { + match result { + Ok(value) => { + ok(value); + None + } + Err(error) => Some(Box::new(wasmtime_error_t { error })), + } +} + +pub(crate) fn bad_utf8() -> Option> { + Some(Box::new(wasmtime_error_t { + error: anyhow!("input was not valid utf-8"), + })) +} + +#[no_mangle] +pub extern "C" fn wasmtime_error_message(error: &wasmtime_error_t, message: &mut wasm_name_t) { + message.set_buffer(format!("{:?}", error.error).into_bytes()); +} diff --git a/crates/c-api/src/func.rs b/crates/c-api/src/func.rs index 18582e243ab5..9c9718216ac3 100644 --- a/crates/c-api/src/func.rs +++ b/crates/c-api/src/func.rs @@ -1,5 +1,6 @@ use crate::{wasm_extern_t, wasm_functype_t, wasm_store_t, wasm_val_t}; -use crate::{wasm_name_t, wasm_trap_t, ExternHost}; +use crate::{wasm_name_t, wasm_trap_t, wasmtime_error_t, ExternHost}; +use anyhow::anyhow; use std::ffi::c_void; use std::panic::{self, AssertUnwindSafe}; use std::ptr; @@ -160,16 +161,54 @@ pub extern "C" fn wasmtime_func_new_with_env( #[no_mangle] pub unsafe extern "C" fn wasm_func_call( - func: &wasm_func_t, + wasm_func: &wasm_func_t, args: *const wasm_val_t, results: *mut wasm_val_t, ) -> *mut wasm_trap_t { + let func = wasm_func.func().borrow(); + let mut trap = ptr::null_mut(); + let error = wasmtime_func_call( + wasm_func, + args, + func.param_arity(), + results, + func.result_arity(), + &mut trap, + ); + match error { + Some(err) => Box::into_raw(err.to_trap()), + None => trap, + } +} + +#[no_mangle] +pub unsafe extern "C" fn wasmtime_func_call( + func: &wasm_func_t, + args: *const wasm_val_t, + num_args: usize, + results: *mut wasm_val_t, + num_results: usize, + trap_ptr: &mut *mut wasm_trap_t, +) -> Option> { + _wasmtime_func_call( + func, + std::slice::from_raw_parts(args, num_args), + std::slice::from_raw_parts_mut(results, num_results), + trap_ptr, + ) +} + +fn _wasmtime_func_call( + func: &wasm_func_t, + args: &[wasm_val_t], + results: &mut [wasm_val_t], + trap_ptr: &mut *mut wasm_trap_t, +) -> Option> { let func = func.func().borrow(); - let mut params = Vec::with_capacity(func.param_arity()); - for i in 0..func.param_arity() { - let val = &(*args.add(i)); - params.push(val.val()); + if results.len() != func.result_arity() { + return Some(Box::new(anyhow!("wrong number of results provided").into())); } + let params = args.iter().map(|i| i.val()).collect::>(); // We're calling arbitrary code here most of the time, and we in general // want to try to insulate callers against bugs in wasmtime/wasi/etc if we @@ -178,18 +217,18 @@ pub unsafe extern "C" fn wasm_func_call( let result = panic::catch_unwind(AssertUnwindSafe(|| func.call(¶ms))); match result { Ok(Ok(out)) => { - for i in 0..func.result_arity() { - let val = &mut (*results.add(i)); - *val = wasm_val_t::from_val(&out[i]); + for (slot, val) in results.iter_mut().zip(out.iter()) { + *slot = wasm_val_t::from_val(val); } - ptr::null_mut() - } - Ok(Err(trap)) => { - let trap = Box::new(wasm_trap_t { - trap: HostRef::new(trap), - }); - Box::into_raw(trap) + None } + Ok(Err(trap)) => match trap.downcast::() { + Ok(trap) => { + *trap_ptr = Box::into_raw(Box::new(wasm_trap_t::new(trap))); + None + } + Err(err) => Some(Box::new(err.into())), + }, Err(panic) => { let trap = if let Some(msg) = panic.downcast_ref::() { Trap::new(msg) @@ -198,10 +237,9 @@ pub unsafe extern "C" fn wasm_func_call( } else { Trap::new("rust panic happened") }; - let trap = Box::new(wasm_trap_t { - trap: HostRef::new(trap), - }); - Box::into_raw(trap) + let trap = Box::new(wasm_trap_t::new(trap)); + *trap_ptr = Box::into_raw(trap); + None } } } diff --git a/crates/c-api/src/global.rs b/crates/c-api/src/global.rs index 9525ec028b0d..4c6f025d65b3 100644 --- a/crates/c-api/src/global.rs +++ b/crates/c-api/src/global.rs @@ -1,4 +1,6 @@ +use crate::{handle_result, wasmtime_error_t}; use crate::{wasm_extern_t, wasm_globaltype_t, wasm_store_t, wasm_val_t, ExternHost}; +use std::ptr; use wasmtime::{Global, HostRef}; #[derive(Clone)] @@ -35,13 +37,31 @@ pub extern "C" fn wasm_global_new( gt: &wasm_globaltype_t, val: &wasm_val_t, ) -> Option> { - let global = - HostRef::new(Global::new(&store.store.borrow(), gt.ty().ty.clone(), val.val()).ok()?); - Some(Box::new(wasm_global_t { - ext: wasm_extern_t { - which: ExternHost::Global(global), - }, - })) + let mut global = ptr::null_mut(); + match wasmtime_global_new(store, gt, val, &mut global) { + Some(_err) => None, + None => { + assert!(!global.is_null()); + Some(unsafe { Box::from_raw(global) }) + } + } +} + +#[no_mangle] +pub extern "C" fn wasmtime_global_new( + store: &wasm_store_t, + gt: &wasm_globaltype_t, + val: &wasm_val_t, + ret: &mut *mut wasm_global_t, +) -> Option> { + let global = Global::new(&store.store.borrow(), gt.ty().ty.clone(), val.val()); + handle_result(global, |global| { + *ret = Box::into_raw(Box::new(wasm_global_t { + ext: wasm_extern_t { + which: ExternHost::Global(HostRef::new(global)), + }, + })); + }) } #[no_mangle] @@ -66,3 +86,11 @@ pub extern "C" fn wasm_global_set(g: &wasm_global_t, val: &wasm_val_t) { // FIXME(WebAssembly/wasm-c-api#131) should communicate the error here drop(result); } + +#[no_mangle] +pub extern "C" fn wasmtime_global_set( + g: &wasm_global_t, + val: &wasm_val_t, +) -> Option> { + handle_result(g.global().borrow().set(val.val()), |()| {}) +} diff --git a/crates/c-api/src/instance.rs b/crates/c-api/src/instance.rs index ab80fb469ede..bbeb5626e17e 100644 --- a/crates/c-api/src/instance.rs +++ b/crates/c-api/src/instance.rs @@ -1,5 +1,5 @@ use crate::{wasm_extern_t, wasm_extern_vec_t, wasm_module_t, wasm_trap_t}; -use crate::{wasm_store_t, ExternHost}; +use crate::{wasm_store_t, wasmtime_error_t, ExternHost}; use anyhow::Result; use std::cell::RefCell; use std::ptr; @@ -15,7 +15,7 @@ pub struct wasm_instance_t { wasmtime_c_api_macros::declare_ref!(wasm_instance_t); impl wasm_instance_t { - fn new(instance: Instance) -> wasm_instance_t { + pub(crate) fn new(instance: Instance) -> wasm_instance_t { wasm_instance_t { instance: HostRef::new(instance), exports_cache: RefCell::new(None), @@ -30,59 +30,111 @@ impl wasm_instance_t { #[no_mangle] pub unsafe extern "C" fn wasm_instance_new( store: &wasm_store_t, - module: &wasm_module_t, + wasm_module: &wasm_module_t, imports: *const Box, result: Option<&mut *mut wasm_trap_t>, ) -> Option> { - let mut externs: Vec = Vec::with_capacity((*module).imports.len()); - for i in 0..(*module).imports.len() { - let import = &*imports.add(i); - externs.push(match &import.which { - ExternHost::Func(e) => Extern::Func(e.borrow().clone()), - ExternHost::Table(e) => Extern::Table(e.borrow().clone()), - ExternHost::Global(e) => Extern::Global(e.borrow().clone()), - ExternHost::Memory(e) => Extern::Memory(e.borrow().clone()), - }); - } - let store = &(*store).store.borrow(); - let module = &(*module).module.borrow(); + let store = &store.store.borrow(); + let module = &wasm_module.module.borrow(); if !Store::same(&store, module.store()) { if let Some(result) = result { let trap = Trap::new("wasm_store_t must match store in wasm_module_t"); - let trap = Box::new(wasm_trap_t { - trap: HostRef::new(trap), - }); + let trap = Box::new(wasm_trap_t::new(trap)); *result = Box::into_raw(trap); } return None; } - handle_instantiate(Instance::new(module, &externs), result) + let mut instance = ptr::null_mut(); + let mut trap = ptr::null_mut(); + let err = wasmtime_instance_new( + wasm_module, + imports, + wasm_module.imports.len(), + &mut instance, + &mut trap, + ); + match err { + Some(err) => { + assert!(trap.is_null()); + assert!(instance.is_null()); + if let Some(result) = result { + *result = Box::into_raw(err.to_trap()); + } + None + } + None => { + if instance.is_null() { + assert!(!trap.is_null()); + if let Some(result) = result { + *result = trap; + } else { + drop(Box::from_raw(trap)) + } + None + } else { + assert!(trap.is_null()); + Some(Box::from_raw(instance)) + } + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn wasmtime_instance_new( + module: &wasm_module_t, + imports: *const Box, + num_imports: usize, + instance_ptr: &mut *mut wasm_instance_t, + trap_ptr: &mut *mut wasm_trap_t, +) -> Option> { + _wasmtime_instance_new( + module, + std::slice::from_raw_parts(imports, num_imports), + instance_ptr, + trap_ptr, + ) +} + +fn _wasmtime_instance_new( + module: &wasm_module_t, + imports: &[Box], + instance_ptr: &mut *mut wasm_instance_t, + trap_ptr: &mut *mut wasm_trap_t, +) -> Option> { + let imports = imports + .iter() + .map(|import| match &import.which { + ExternHost::Func(e) => Extern::Func(e.borrow().clone()), + ExternHost::Table(e) => Extern::Table(e.borrow().clone()), + ExternHost::Global(e) => Extern::Global(e.borrow().clone()), + ExternHost::Memory(e) => Extern::Memory(e.borrow().clone()), + }) + .collect::>(); + let module = &module.module.borrow(); + handle_instantiate(Instance::new(module, &imports), instance_ptr, trap_ptr) } pub fn handle_instantiate( instance: Result, - result: Option<&mut *mut wasm_trap_t>, -) -> Option> { + instance_ptr: &mut *mut wasm_instance_t, + trap_ptr: &mut *mut wasm_trap_t, +) -> Option> { + fn write(ptr: &mut *mut T, val: T) { + *ptr = Box::into_raw(Box::new(val)) + } + match instance { Ok(instance) => { - if let Some(result) = result { - *result = ptr::null_mut(); - } - Some(Box::new(wasm_instance_t::new(instance))) - } - Err(trap) => { - if let Some(result) = result { - let trap = match trap.downcast::() { - Ok(trap) => trap, - Err(e) => Trap::new(format!("{:?}", e)), - }; - let trap = Box::new(wasm_trap_t { - trap: HostRef::new(trap), - }); - *result = Box::into_raw(trap); - } + write(instance_ptr, wasm_instance_t::new(instance)); None } + Err(e) => match e.downcast::() { + Ok(trap) => { + write(trap_ptr, wasm_trap_t::new(trap)); + None + } + Err(e) => Some(Box::new(e.into())), + }, } } diff --git a/crates/c-api/src/lib.rs b/crates/c-api/src/lib.rs index b97044836a18..9a62dad2be5d 100644 --- a/crates/c-api/src/lib.rs +++ b/crates/c-api/src/lib.rs @@ -7,6 +7,7 @@ mod config; mod engine; +mod error; mod r#extern; mod func; mod global; @@ -24,6 +25,7 @@ mod vec; pub use crate::config::*; pub use crate::engine::*; +pub use crate::error::*; pub use crate::func::*; pub use crate::global::*; pub use crate::instance::*; diff --git a/crates/c-api/src/linker.rs b/crates/c-api/src/linker.rs index 3d4f71473304..4faee0de8499 100644 --- a/crates/c-api/src/linker.rs +++ b/crates/c-api/src/linker.rs @@ -1,3 +1,4 @@ +use crate::{bad_utf8, handle_result, wasmtime_error_t}; use crate::{wasm_extern_t, wasm_store_t, ExternHost}; use crate::{wasm_instance_t, wasm_module_t, wasm_name_t, wasm_trap_t}; use std::str; @@ -32,15 +33,15 @@ pub extern "C" fn wasmtime_linker_define( module: &wasm_name_t, name: &wasm_name_t, item: &wasm_extern_t, -) -> bool { +) -> Option> { let linker = &mut linker.linker; let module = match str::from_utf8(module.as_slice()) { Ok(s) => s, - Err(_) => return false, + Err(_) => return bad_utf8(), }; let name = match str::from_utf8(name.as_slice()) { Ok(s) => s, - Err(_) => return false, + Err(_) => return bad_utf8(), }; let item = match &item.which { ExternHost::Func(e) => Extern::Func(e.borrow().clone()), @@ -48,7 +49,7 @@ pub extern "C" fn wasmtime_linker_define( ExternHost::Global(e) => Extern::Global(e.borrow().clone()), ExternHost::Memory(e) => Extern::Memory(e.borrow().clone()), }; - linker.define(module, name, item).is_ok() + handle_result(linker.define(module, name, item), |_linker| ()) } #[cfg(feature = "wasi")] @@ -56,9 +57,9 @@ pub extern "C" fn wasmtime_linker_define( pub extern "C" fn wasmtime_linker_define_wasi( linker: &mut wasmtime_linker_t, instance: &crate::wasi_instance_t, -) -> bool { +) -> Option> { let linker = &mut linker.linker; - instance.add_to_linker(linker).is_ok() + handle_result(instance.add_to_linker(linker), |_linker| ()) } #[no_mangle] @@ -66,22 +67,25 @@ pub extern "C" fn wasmtime_linker_define_instance( linker: &mut wasmtime_linker_t, name: &wasm_name_t, instance: &wasm_instance_t, -) -> bool { +) -> Option> { let linker = &mut linker.linker; let name = match str::from_utf8(name.as_slice()) { Ok(s) => s, - Err(_) => return false, + Err(_) => return bad_utf8(), }; - linker.instance(name, &instance.instance.borrow()).is_ok() + handle_result( + linker.instance(name, &instance.instance.borrow()), + |_linker| (), + ) } #[no_mangle] pub unsafe extern "C" fn wasmtime_linker_instantiate( linker: &wasmtime_linker_t, module: &wasm_module_t, - trap: Option<&mut *mut wasm_trap_t>, -) -> Option> { - let linker = &linker.linker; - let result = linker.instantiate(&module.module.borrow()); - super::instance::handle_instantiate(result, trap) + instance_ptr: &mut *mut wasm_instance_t, + trap_ptr: &mut *mut wasm_trap_t, +) -> Option> { + let result = linker.linker.instantiate(&module.module.borrow()); + super::instance::handle_instantiate(result, instance_ptr, trap_ptr) } diff --git a/crates/c-api/src/module.rs b/crates/c-api/src/module.rs index 4cf15bda06ea..4d1b2ec0c8fb 100644 --- a/crates/c-api/src/module.rs +++ b/crates/c-api/src/module.rs @@ -1,5 +1,7 @@ +use crate::{handle_result, wasmtime_error_t}; use crate::{wasm_byte_vec_t, wasm_exporttype_vec_t, wasm_importtype_vec_t}; use crate::{wasm_exporttype_t, wasm_importtype_t, wasm_store_t}; +use std::ptr; use wasmtime::{HostRef, Module}; #[repr(C)] @@ -23,31 +25,57 @@ pub extern "C" fn wasm_module_new( store: &wasm_store_t, binary: &wasm_byte_vec_t, ) -> Option> { + let mut ret = ptr::null_mut(); + match wasmtime_module_new(store, binary, &mut ret) { + Some(_err) => None, + None => { + assert!(!ret.is_null()); + Some(unsafe { Box::from_raw(ret) }) + } + } +} + +#[no_mangle] +pub extern "C" fn wasmtime_module_new( + store: &wasm_store_t, + binary: &wasm_byte_vec_t, + ret: &mut *mut wasm_module_t, +) -> Option> { let binary = binary.as_slice(); let store = &store.store.borrow(); - let module = Module::from_binary(store, binary).ok()?; - let imports = module - .imports() - .iter() - .map(|i| wasm_importtype_t::new(i.clone())) - .collect::>(); - let exports = module - .exports() - .iter() - .map(|e| wasm_exporttype_t::new(e.clone())) - .collect::>(); - Some(Box::new(wasm_module_t { - module: HostRef::new(module), - imports, - exports, - })) + handle_result(Module::from_binary(store, binary), |module| { + let imports = module + .imports() + .iter() + .map(|i| wasm_importtype_t::new(i.clone())) + .collect::>(); + let exports = module + .exports() + .iter() + .map(|e| wasm_exporttype_t::new(e.clone())) + .collect::>(); + let module = Box::new(wasm_module_t { + module: HostRef::new(module), + imports, + exports, + }); + *ret = Box::into_raw(module); + }) } #[no_mangle] pub extern "C" fn wasm_module_validate(store: &wasm_store_t, binary: &wasm_byte_vec_t) -> bool { + wasmtime_module_validate(store, binary).is_none() +} + +#[no_mangle] +pub extern "C" fn wasmtime_module_validate( + store: &wasm_store_t, + binary: &wasm_byte_vec_t, +) -> Option> { let binary = binary.as_slice(); let store = &store.store.borrow(); - Module::validate(store, binary).is_ok() + handle_result(Module::validate(store, binary), |()| {}) } #[no_mangle] diff --git a/crates/c-api/src/trap.rs b/crates/c-api/src/trap.rs index d41d676dbbe0..51b82fe6aa2c 100644 --- a/crates/c-api/src/trap.rs +++ b/crates/c-api/src/trap.rs @@ -11,6 +11,12 @@ pub struct wasm_trap_t { wasmtime_c_api_macros::declare_ref!(wasm_trap_t); impl wasm_trap_t { + pub(crate) fn new(trap: Trap) -> wasm_trap_t { + wasm_trap_t { + trap: HostRef::new(trap), + } + } + fn anyref(&self) -> wasmtime::AnyRef { self.trap.anyref() } diff --git a/crates/c-api/src/wat2wasm.rs b/crates/c-api/src/wat2wasm.rs index 19ab2c8ffd7e..696ee579a8e7 100644 --- a/crates/c-api/src/wat2wasm.rs +++ b/crates/c-api/src/wat2wasm.rs @@ -1,30 +1,15 @@ -use crate::wasm_byte_vec_t; +use crate::{bad_utf8, handle_result, wasm_byte_vec_t, wasmtime_error_t}; #[no_mangle] pub extern "C" fn wasmtime_wat2wasm( wat: &wasm_byte_vec_t, ret: &mut wasm_byte_vec_t, - error: Option<&mut wasm_byte_vec_t>, -) -> bool { +) -> Option> { let wat = match std::str::from_utf8(wat.as_slice()) { Ok(s) => s, - Err(_) => { - if let Some(error) = error { - error.set_buffer(b"input was not valid utf-8".to_vec()); - } - return false; - } + Err(_) => return bad_utf8(), }; - match wat::parse_str(wat) { - Ok(bytes) => { - ret.set_buffer(bytes.into()); - true - } - Err(e) => { - if let Some(error) = error { - error.set_buffer(e.to_string().into_bytes()); - } - false - } - } + handle_result(wat::parse_str(wat).map_err(|e| e.into()), |bytes| { + ret.set_buffer(bytes.into()) + }) } diff --git a/crates/fuzzing/src/oracles.rs b/crates/fuzzing/src/oracles.rs index f57f13c0eb87..cf3405365dcb 100644 --- a/crates/fuzzing/src/oracles.rs +++ b/crates/fuzzing/src/oracles.rs @@ -198,7 +198,7 @@ pub fn differential_execution( Ok(p) => p, Err(_) => continue, }; - let this_result = f.call(¶ms); + let this_result = f.call(¶ms).map_err(|e| e.downcast::().unwrap()); let existing_result = export_func_results .entry(name.to_string()) diff --git a/crates/misc/dotnet/src/Host.cs b/crates/misc/dotnet/src/Host.cs index 95d6e9804244..b036f542f85f 100644 --- a/crates/misc/dotnet/src/Host.cs +++ b/crates/misc/dotnet/src/Host.cs @@ -43,9 +43,10 @@ public void DefineWasi(string name, WasiConfiguration config = null) using var wasi = config.CreateWasi(Store, name); - if (!Interop.wasmtime_linker_define_wasi(Linker, wasi)) + var error = Interop.wasmtime_linker_define_wasi(Linker, wasi); + if (error != IntPtr.Zero) { - throw new WasmtimeException($"Failed to define WASI module '{name}'."); + throw WasmtimeException.FromOwnedError(error); } } @@ -618,12 +619,10 @@ public Module LoadModuleText(string name, string text) textVec.size = (UIntPtr)textBytes.Length; textVec.data = ptr; - if (!Interop.wasmtime_wat2wasm(ref textVec, out var bytes, out var error)) + var error = Interop.wasmtime_wat2wasm(ref textVec, out var bytes); + if (error != IntPtr.Zero) { - var errorSpan = new ReadOnlySpan(error.data, checked((int)error.size)); - var message = Encoding.UTF8.GetString(errorSpan); - Interop.wasm_byte_vec_delete(ref error); - throw new WasmtimeException($"Failed to parse module text: {message}"); + throw WasmtimeException.FromOwnedError(error); } var byteSpan = new ReadOnlySpan(bytes.data, checked((int)bytes.size)); @@ -792,7 +791,11 @@ private bool Define(string moduleName, string name, IntPtr ext) nameVec.size = (UIntPtr)nameBytes.Length; nameVec.data = namePtr; - return Interop.wasmtime_linker_define(Linker, ref moduleNameVec, ref nameVec, ext); + var error = Interop.wasmtime_linker_define(Linker, ref moduleNameVec, ref nameVec, ext); + if (error == IntPtr.Zero) + return true; + Interop.wasmtime_error_delete(error); + return false; } } } diff --git a/crates/misc/dotnet/src/Instance.cs b/crates/misc/dotnet/src/Instance.cs index 92232d3c0fab..8221656378b0 100644 --- a/crates/misc/dotnet/src/Instance.cs +++ b/crates/misc/dotnet/src/Instance.cs @@ -80,8 +80,13 @@ internal Instance(Interop.LinkerHandle linker, Module module) unsafe { - Handle = Interop.wasmtime_linker_instantiate(linker, module.Handle, out var trap); + var error = Interop.wasmtime_linker_instantiate(linker, module.Handle, out var handle, out var trap); + Handle = handle; + if (error != IntPtr.Zero) + { + throw WasmtimeException.FromOwnedError(error); + } if (trap != IntPtr.Zero) { throw TrapException.FromOwnedTrap(trap); diff --git a/crates/misc/dotnet/src/Interop.cs b/crates/misc/dotnet/src/Interop.cs index 32f92585eda4..3978d66e955c 100644 --- a/crates/misc/dotnet/src/Interop.cs +++ b/crates/misc/dotnet/src/Interop.cs @@ -268,6 +268,21 @@ protected override bool ReleaseHandle() } } + internal class ErrorHandle : SafeHandle + { + public ErrorHandle() : base(IntPtr.Zero, true) + { + } + + public override bool IsInvalid => handle == IntPtr.Zero; + + protected override bool ReleaseHandle() + { + Interop.wasmtime_error_delete(handle); + return true; + } + } + [StructLayout(LayoutKind.Sequential)] internal unsafe struct wasm_byte_vec_t { @@ -1003,7 +1018,7 @@ out IntPtr trap public static extern void wasmtime_config_wasm_multi_value_set(WasmConfigHandle config, [MarshalAs(UnmanagedType.I1)] bool enable); [DllImport(LibraryName)] - public static extern void wasmtime_config_strategy_set(WasmConfigHandle config, wasmtime_strategy_t strategy); + public static extern IntPtr wasmtime_config_strategy_set(WasmConfigHandle config, wasmtime_strategy_t strategy); [DllImport(LibraryName)] public static extern void wasmtime_config_cranelift_debug_verifier_set(WasmConfigHandle config, [MarshalAs(UnmanagedType.I1)] bool enable); @@ -1013,9 +1028,8 @@ out IntPtr trap // Utility functions - [DllImport(LibraryName, CharSet=CharSet.Ansi)] - [return: MarshalAs(UnmanagedType.I1)] - public static extern bool wasmtime_wat2wasm(ref wasm_byte_vec_t text, out wasm_byte_vec_t bytes, out wasm_byte_vec_t error); + [DllImport(LibraryName)] + public static extern IntPtr wasmtime_wat2wasm(ref wasm_byte_vec_t text, out wasm_byte_vec_t bytes); // Linking functions @@ -1029,19 +1043,16 @@ out IntPtr trap public static extern void wasmtime_linker_delete(IntPtr linker); [DllImport(LibraryName)] - [return: MarshalAs(UnmanagedType.I1)] - public static extern bool wasmtime_linker_define(LinkerHandle linker, ref wasm_byte_vec_t module, ref wasm_byte_vec_t name, IntPtr externType); + public static extern IntPtr wasmtime_linker_define(LinkerHandle linker, ref wasm_byte_vec_t module, ref wasm_byte_vec_t name, IntPtr externType); [DllImport(LibraryName)] - [return: MarshalAs(UnmanagedType.I1)] - public static extern bool wasmtime_linker_define_wasi(LinkerHandle linker, WasiInstanceHandle wasi); + public static extern IntPtr wasmtime_linker_define_wasi(LinkerHandle linker, WasiInstanceHandle wasi); [DllImport(LibraryName)] - [return: MarshalAs(UnmanagedType.I1)] - public static extern bool wasmtime_linker_define_instance(LinkerHandle linker, ref wasm_byte_vec_t name, InstanceHandle instance); + public static extern IntPtr wasmtime_linker_define_instance(LinkerHandle linker, ref wasm_byte_vec_t name, InstanceHandle instance); [DllImport(LibraryName)] - public static extern InstanceHandle wasmtime_linker_instantiate(LinkerHandle linker, ModuleHandle module, out IntPtr trap); + public static extern IntPtr wasmtime_linker_instantiate(LinkerHandle linker, ModuleHandle module, out InstanceHandle instance, out IntPtr trap); // Caller functions @@ -1050,5 +1061,11 @@ out IntPtr trap [DllImport(LibraryName)] public static extern ExternHandle wasmtime_caller_export_get(IntPtr caller, ref wasm_byte_vec_t name); + + [DllImport(LibraryName)] + public static extern void wasmtime_error_message(IntPtr error, out wasm_byte_vec_t message); + + [DllImport(LibraryName)] + public static extern void wasmtime_error_delete(IntPtr error); } } diff --git a/crates/misc/dotnet/src/WasmtimeException.cs b/crates/misc/dotnet/src/WasmtimeException.cs index 26f0e6c5e663..7494a5264c1b 100644 --- a/crates/misc/dotnet/src/WasmtimeException.cs +++ b/crates/misc/dotnet/src/WasmtimeException.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.Serialization; +using System.Text; namespace Wasmtime { @@ -20,5 +21,20 @@ public WasmtimeException(string message, Exception inner) : base(message, inner) /// protected WasmtimeException(SerializationInfo info, StreamingContext context) : base(info, context) { } + + internal static WasmtimeException FromOwnedError(IntPtr error) + { + unsafe + { + Interop.wasmtime_error_message(error, out var bytes); + var byteSpan = new ReadOnlySpan(bytes.data, checked((int)bytes.size)); + var message = Encoding.UTF8.GetString(byteSpan); + Interop.wasm_byte_vec_delete(ref bytes); + + Interop.wasmtime_error_delete(error); + + return new WasmtimeException(message); + } + } } } diff --git a/crates/wast/src/wast.rs b/crates/wast/src/wast.rs index 456b9a2dfa4a..7544c6255ca3 100644 --- a/crates/wast/src/wast.rs +++ b/crates/wast/src/wast.rs @@ -154,7 +154,7 @@ impl WastContext { .ok_or_else(|| anyhow!("no function named `{}`", field))?; Ok(match func.call(args) { Ok(result) => Outcome::Ok(result.into()), - Err(e) => Outcome::Trap(e), + Err(e) => Outcome::Trap(e.downcast()?), }) } diff --git a/examples/fib-debug/main.c b/examples/fib-debug/main.c index 95960ab44cce..dfebf8993e4c 100644 --- a/examples/fib-debug/main.c +++ b/examples/fib-debug/main.c @@ -8,6 +8,8 @@ #define own +static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap); + int main(int argc, const char* argv[]) { // Configuring engine to support generating of DWARF info. // lldb can be used to attach to the program and observe @@ -40,11 +42,10 @@ int main(int argc, const char* argv[]) { // Compile. printf("Compiling module...\n"); - own wasm_module_t* module = wasm_module_new(store, &binary); - if (!module) { - printf("> Error compiling module!\n"); - return 1; - } + wasm_module_t *module = NULL; + wasmtime_error_t* error = wasmtime_module_new(store, &binary, &module); + if (!module) + exit_with_error("failed to compile module", error, NULL); wasm_byte_vec_delete(&binary); // Figure out which export is the `fib` export @@ -68,12 +69,12 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - own wasm_instance_t* instance = - wasm_instance_new(store, module, NULL, NULL); - if (!instance) { - printf("> Error instantiating module!\n"); - return 1; - } + wasm_instance_t* instance = NULL; + wasm_trap_t *trap = NULL; + error = wasmtime_instance_new(module, NULL, 0, &instance, &trap); + if (error != NULL || trap != NULL) + exit_with_error("failed to instantiate", error, trap); + wasm_module_delete(module); // Extract export. printf("Extracting export...\n"); @@ -84,23 +85,21 @@ int main(int argc, const char* argv[]) { return 1; } // Getting second export (first is memory). - const wasm_func_t* run_func = wasm_extern_as_func(exports.data[fib_idx]); + wasm_func_t* run_func = wasm_extern_as_func(exports.data[fib_idx]); if (run_func == NULL) { printf("> Error accessing export!\n"); return 1; } - wasm_module_delete(module); wasm_instance_delete(instance); // Call. printf("Calling fib...\n"); wasm_val_t params[1] = { {.kind = WASM_I32, .of = {.i32 = 6}} }; wasm_val_t results[1]; - if (wasm_func_call(run_func, params, results)) { - printf("> Error calling function!\n"); - return 1; - } + error = wasmtime_func_call(run_func, params, 1, results, 1, &trap); + if (error != NULL || trap != NULL) + exit_with_error("failed to call function", error, trap); wasm_extern_vec_delete(&exports); @@ -116,3 +115,15 @@ int main(int argc, const char* argv[]) { return 0; } +static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) { + fprintf(stderr, "error: %s\n", message); + wasm_byte_vec_t error_message; + if (error != NULL) { + wasmtime_error_message(error, &error_message); + } else { + wasm_trap_message(trap, &error_message); + } + fprintf(stderr, "%.*s\n", (int) error_message.size, error_message.data); + wasm_byte_vec_delete(&error_message); + exit(1); +} diff --git a/examples/gcd.c b/examples/gcd.c index b61fd751990a..c4b6beb69c74 100644 --- a/examples/gcd.c +++ b/examples/gcd.c @@ -23,7 +23,7 @@ to tweak the `-lpthread` and such annotations. #include #include -static void print_trap(wasm_trap_t *trap); +static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap); int main() { int ret = 0; @@ -51,23 +51,23 @@ int main() { fclose(file); // Parse the wat into the binary wasm format - wasm_byte_vec_t wasm, error; - if (wasmtime_wat2wasm(&wat, &wasm, &error) == 0) { - fprintf(stderr, "failed to parse wat %.*s\n", (int) error.size, error.data); - goto free_store; - } + wasm_byte_vec_t wasm; + wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &wasm); + if (error != NULL) + exit_with_error("failed to parse wat", error, NULL); wasm_byte_vec_delete(&wat); // Compile and instantiate our module - wasm_module_t *module = wasm_module_new(store, &wasm); + wasm_module_t *module = NULL; + error = wasmtime_module_new(store, &wasm, &module); + if (module == NULL) + exit_with_error("failed to compile module", error, NULL); wasm_byte_vec_delete(&wasm); - assert(module != NULL); wasm_trap_t *trap = NULL; - wasm_instance_t *instance = wasm_instance_new(store, module, NULL, &trap); - if (instance == NULL) { - print_trap(trap); - goto free_module; - } + wasm_instance_t *instance = NULL; + error = wasmtime_instance_new(module, NULL, 0, &instance, &trap); + if (instance == NULL) + exit_with_error("failed to instantiate", error, trap); // Lookup our `gcd` export function wasm_extern_vec_t externs; @@ -85,11 +85,9 @@ int main() { params[0].of.i32 = a; params[1].kind = WASM_I32; params[1].of.i32 = b; - trap = wasm_func_call(gcd, params, results); - if (trap != NULL) { - print_trap(trap); - goto free_instance; - } + error = wasmtime_func_call(gcd, params, 2, results, 1, &trap); + if (error != NULL || trap != NULL) + exit_with_error("failed to call gcd", error, trap); assert(results[0].kind == WASM_I32); printf("gcd(%d, %d) = %d\n", a, b, results[0].of.i32); @@ -97,22 +95,23 @@ int main() { // Clean up after ourselves at this point ret = 0; -free_instance: wasm_extern_vec_delete(&externs); wasm_instance_delete(instance); -free_module: wasm_module_delete(module); -free_store: wasm_store_delete(store); wasm_engine_delete(engine); return ret; } -static void print_trap(wasm_trap_t *trap) { - assert(trap != NULL); - wasm_message_t message; - wasm_trap_message(trap, &message); - fprintf(stderr, "failed to instantiate module %.*s\n", (int) message.size, message.data); - wasm_byte_vec_delete(&message); - wasm_trap_delete(trap); +static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) { + fprintf(stderr, "error: %s\n", message); + wasm_byte_vec_t error_message; + if (error != NULL) { + wasmtime_error_message(error, &error_message); + } else { + wasm_trap_message(trap, &error_message); + } + fprintf(stderr, "%.*s\n", (int) error_message.size, error_message.data); + wasm_byte_vec_delete(&error_message); + exit(1); } diff --git a/examples/hello.c b/examples/hello.c index f596bee6a816..2082247203f8 100644 --- a/examples/hello.c +++ b/examples/hello.c @@ -24,7 +24,7 @@ to tweak the `-lpthread` and such annotations as well as the name of the #include #include -static void print_trap(wasm_trap_t *trap); +static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap); static wasm_trap_t* hello_callback(const wasm_val_t args[], wasm_val_t results[]) { printf("Calling back...\n"); @@ -58,18 +58,19 @@ int main() { fclose(file); // Parse the wat into the binary wasm format - wasm_byte_vec_t wasm, error; - if (wasmtime_wat2wasm(&wat, &wasm, &error) == 0) { - fprintf(stderr, "failed to parse wat %.*s\n", (int) error.size, error.data); - goto free_store; - } + wasm_byte_vec_t wasm; + wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &wasm); + if (error != NULL) + exit_with_error("failed to parse wat", error, NULL); wasm_byte_vec_delete(&wat); // Now that we've got our binary webassembly we can compile our module. printf("Compiling module...\n"); - wasm_module_t *module = wasm_module_new(store, &wasm); + wasm_module_t *module = NULL; + error = wasmtime_module_new(store, &wasm, &module); wasm_byte_vec_delete(&wasm); - assert(module != NULL); + if (error != NULL) + exit_with_error("failed to compile module", error, NULL); // Next up we need to create the function that the wasm module imports. Here // we'll be hooking up a thunk function to the `hello_callback` native @@ -84,12 +85,11 @@ int main() { // to handle that here too. printf("Instantiating module...\n"); wasm_trap_t *trap = NULL; + wasm_instance_t *instance = NULL; const wasm_extern_t *imports[] = { wasm_func_as_extern(hello) }; - wasm_instance_t *instance = wasm_instance_new(store, module, imports, &trap); - if (instance == NULL) { - print_trap(trap); - goto free_module; - } + error = wasmtime_instance_new(module, imports, 1, &instance, &trap); + if (instance == NULL) + exit_with_error("failed to instantiate", error, trap); // Lookup our `run` export function printf("Extracting export...\n"); @@ -101,33 +101,33 @@ int main() { // And call it! printf("Calling export...\n"); - trap = wasm_func_call(run, NULL, NULL); - if (trap != NULL) { - print_trap(trap); - goto free_instance; - } + error = wasmtime_func_call(run, NULL, 0, NULL, 0, &trap); + if (error != NULL || trap != NULL) + exit_with_error("failed to call function", error, trap); // Clean up after ourselves at this point printf("All finished!\n"); ret = 0; -free_instance: wasm_extern_vec_delete(&externs); wasm_instance_delete(instance); -free_module: wasm_module_delete(module); -free_store: wasm_store_delete(store); wasm_engine_delete(engine); return ret; } -static void print_trap(wasm_trap_t *trap) { - assert(trap != NULL); - wasm_message_t message; - wasm_trap_message(trap, &message); - fprintf(stderr, "failed to instantiate module %.*s\n", (int) message.size, message.data); - wasm_byte_vec_delete(&message); - wasm_trap_delete(trap); +static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) { + fprintf(stderr, "error: %s\n", message); + wasm_byte_vec_t error_message; + if (error != NULL) { + wasmtime_error_message(error, &error_message); + wasmtime_error_delete(error); + } else { + wasm_trap_message(trap, &error_message); + wasm_trap_delete(trap); + } + fprintf(stderr, "%.*s\n", (int) error_message.size, error_message.data); + wasm_byte_vec_delete(&error_message); + exit(1); } - diff --git a/examples/linking.c b/examples/linking.c index f3dc19942982..7e6a29aed055 100644 --- a/examples/linking.c +++ b/examples/linking.c @@ -26,7 +26,7 @@ to tweak the `-lpthread` and such annotations. #define MIN(a, b) ((a) < (b) ? (a) : (b)) -static void print_trap(wasm_trap_t *trap); +static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap); static void read_wat_file(wasm_engine_t *engine, wasm_byte_vec_t *bytes, const char *file); int main() { @@ -42,10 +42,15 @@ int main() { read_wat_file(engine, &linking2_wasm, "examples/linking2.wat"); // Compile our two modules - wasm_module_t *linking1_module = wasm_module_new(store, &linking1_wasm); - assert(linking1_module != NULL); - wasm_module_t *linking2_module = wasm_module_new(store, &linking2_wasm); - assert(linking2_module != NULL); + wasmtime_error_t *error; + wasm_module_t *linking1_module = NULL; + wasm_module_t *linking2_module = NULL; + error = wasmtime_module_new(store, &linking1_wasm, &linking1_module); + if (error != NULL) + exit_with_error("failed to compile linking1", error, NULL); + error = wasmtime_module_new(store, &linking2_wasm, &linking2_module); + if (error != NULL) + exit_with_error("failed to compile linking2", error, NULL); wasm_byte_vec_delete(&linking1_wasm); wasm_byte_vec_delete(&linking2_wasm); @@ -59,45 +64,35 @@ int main() { wasi_config_inherit_stderr(wasi_config); wasm_trap_t *trap = NULL; wasi_instance_t *wasi = wasi_instance_new(store, "wasi_snapshot_preview1", wasi_config, &trap); - if (wasi == NULL) { - print_trap(trap); - exit(1); - } + if (wasi == NULL) + exit_with_error("failed to instantiate wasi", NULL, trap); // Create our linker which will be linking our modules together, and then add // our WASI instance to it. wasmtime_linker_t *linker = wasmtime_linker_new(store); - bool ok = wasmtime_linker_define_wasi(linker, wasi); - assert(ok); + error = wasmtime_linker_define_wasi(linker, wasi); + if (error != NULL) + exit_with_error("failed to link wasi", error, NULL); // Instantiate `linking2` with our linker. - wasm_instance_t *linking2 = wasmtime_linker_instantiate(linker, linking2_module, &trap); - if (linking2 == NULL) { - if (trap == NULL) { - printf("> failed to link!\n"); - } else { - print_trap(trap); - } - exit(1); - } + wasm_instance_t *linking2; + error = wasmtime_linker_instantiate(linker, linking2_module, &linking2, &trap); + if (error != NULL || trap != NULL) + exit_with_error("failed to instantiate linking2", error, trap); // Register our new `linking2` instance with the linker wasm_name_t linking2_name; linking2_name.data = "linking2"; linking2_name.size = strlen(linking2_name.data); - ok = wasmtime_linker_define_instance(linker, &linking2_name, linking2); - assert(ok); + error = wasmtime_linker_define_instance(linker, &linking2_name, linking2); + if (error != NULL) + exit_with_error("failed to link linking2", error, NULL); // Instantiate `linking1` with the linker now that `linking2` is defined - wasm_instance_t *linking1 = wasmtime_linker_instantiate(linker, linking1_module, &trap); - if (linking1 == NULL) { - if (trap == NULL) { - printf("> failed to link!\n"); - } else { - print_trap(trap); - } - exit(1); - } + wasm_instance_t *linking1; + error = wasmtime_linker_instantiate(linker, linking1_module, &linking1, &trap); + if (error != NULL || trap != NULL) + exit_with_error("failed to instantiate linking1", error, trap); // Lookup our `run` export function wasm_extern_vec_t linking1_externs; @@ -105,11 +100,9 @@ int main() { assert(linking1_externs.size == 1); wasm_func_t *run = wasm_extern_as_func(linking1_externs.data[0]); assert(run != NULL); - trap = wasm_func_call(run, NULL, NULL); - if (trap != NULL) { - print_trap(trap); - exit(1); - } + error = wasmtime_func_call(run, NULL, 0, NULL, 0, &trap); + if (error != NULL || trap != NULL) + exit_with_error("failed to call run", error, trap); // Clean up after ourselves at this point wasm_extern_vec_delete(&linking1_externs); @@ -146,19 +139,23 @@ static void read_wat_file( fclose(file); // Parse the wat into the binary wasm format - wasm_byte_vec_t error; - if (wasmtime_wat2wasm(&wat, bytes, &error) == 0) { - fprintf(stderr, "failed to parse wat %.*s\n", (int) error.size, error.data); - exit(1); - } + wasmtime_error_t *error = wasmtime_wat2wasm(&wat, bytes); + if (error != NULL) + exit_with_error("failed to parse wat", error, NULL); wasm_byte_vec_delete(&wat); } -static void print_trap(wasm_trap_t *trap) { - assert(trap != NULL); - wasm_message_t message; - wasm_trap_message(trap, &message); - fprintf(stderr, "failed to instantiate module %.*s\n", (int) message.size, message.data); - wasm_byte_vec_delete(&message); - wasm_trap_delete(trap); +static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) { + fprintf(stderr, "error: %s\n", message); + wasm_byte_vec_t error_message; + if (error != NULL) { + wasmtime_error_message(error, &error_message); + wasmtime_error_delete(error); + } else { + wasm_trap_message(trap, &error_message); + wasm_trap_delete(trap); + } + fprintf(stderr, "%.*s\n", (int) error_message.size, error_message.data); + wasm_byte_vec_delete(&error_message); + exit(1); } diff --git a/examples/memory.c b/examples/memory.c index 7174d17aba35..1687048f9254 100644 --- a/examples/memory.c +++ b/examples/memory.c @@ -28,6 +28,7 @@ originally #include #include +static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap); wasm_memory_t* get_export_memory(const wasm_extern_vec_t* exports, size_t i) { if (exports->size <= i || !wasm_extern_as_memory(exports->data[i])) { @@ -53,21 +54,25 @@ void check(bool success) { } } -void check_call(wasm_func_t* func, wasm_val_t args[], int32_t expected) { +void check_call(wasm_func_t* func, wasm_val_t args[], size_t num_args, int32_t expected) { wasm_val_t results[1]; - if (wasm_func_call(func, args, results) || results[0].of.i32 != expected) { + wasm_trap_t *trap = NULL; + wasmtime_error_t *error = wasmtime_func_call(func, args, num_args, results, 1, &trap); + if (error != NULL || trap != NULL) + exit_with_error("failed to call function", error, trap); + if (results[0].of.i32 != expected) { printf("> Error on result\n"); exit(1); } } void check_call0(wasm_func_t* func, int32_t expected) { - check_call(func, NULL, expected); + check_call(func, NULL, 0, expected); } void check_call1(wasm_func_t* func, int32_t arg, int32_t expected) { wasm_val_t args[] = { {.kind = WASM_I32, .of = {.i32 = arg}} }; - check_call(func, args, expected); + check_call(func, args, 1, expected); } void check_call2(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) { @@ -75,14 +80,14 @@ void check_call2(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected {.kind = WASM_I32, .of = {.i32 = arg1}}, {.kind = WASM_I32, .of = {.i32 = arg2}} }; - check_call(func, args, expected); + check_call(func, args, 2, expected); } -void check_ok(wasm_func_t* func, wasm_val_t args[]) { - if (wasm_func_call(func, args, NULL)) { - printf("> Error on result, expected empty\n"); - exit(1); - } +void check_ok(wasm_func_t* func, wasm_val_t args[], size_t num_args) { + wasm_trap_t *trap = NULL; + wasmtime_error_t *error = wasmtime_func_call(func, args, num_args, NULL, 0, &trap); + if (error != NULL || trap != NULL) + exit_with_error("failed to call function", error, trap); } void check_ok2(wasm_func_t* func, int32_t arg1, int32_t arg2) { @@ -90,13 +95,17 @@ void check_ok2(wasm_func_t* func, int32_t arg1, int32_t arg2) { {.kind = WASM_I32, .of = {.i32 = arg1}}, {.kind = WASM_I32, .of = {.i32 = arg2}} }; - check_ok(func, args); + check_ok(func, args, 2); } -void check_trap(wasm_func_t* func, wasm_val_t args[]) { +void check_trap(wasm_func_t* func, wasm_val_t args[], size_t num_args, size_t num_results) { wasm_val_t results[1]; - wasm_trap_t* trap = wasm_func_call(func, args, results); - if (! trap) { + assert(num_results <= 1); + wasm_trap_t *trap = NULL; + wasmtime_error_t *error = wasmtime_func_call(func, args, num_args, results, num_results, &trap); + if (error != NULL) + exit_with_error("failed to call function", error, NULL); + if (trap == NULL) { printf("> Error on result, expected trap\n"); exit(1); } @@ -105,7 +114,7 @@ void check_trap(wasm_func_t* func, wasm_val_t args[]) { void check_trap1(wasm_func_t* func, int32_t arg) { wasm_val_t args[1] = { {.kind = WASM_I32, .of = {.i32 = arg}} }; - check_trap(func, args); + check_trap(func, args, 1, 1); } void check_trap2(wasm_func_t* func, int32_t arg1, int32_t arg2) { @@ -113,7 +122,7 @@ void check_trap2(wasm_func_t* func, int32_t arg1, int32_t arg2) { {.kind = WASM_I32, .of = {.i32 = arg1}}, {.kind = WASM_I32, .of = {.i32 = arg2}} }; - check_trap(func, args); + check_trap(func, args, 2, 0); } int main(int argc, const char* argv[]) { @@ -140,30 +149,27 @@ int main(int argc, const char* argv[]) { fclose(file); // Parse the wat into the binary wasm format - wasm_byte_vec_t binary, error; - if (wasmtime_wat2wasm(&wat, &binary, &error) == 0) { - fprintf(stderr, "failed to parse wat %.*s\n", (int) error.size, error.data); - return 1; - } + wasm_byte_vec_t binary; + wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &binary); + if (error != NULL) + exit_with_error("failed to parse wat", error, NULL); wasm_byte_vec_delete(&wat); // Compile. printf("Compiling module...\n"); - wasm_module_t* module = wasm_module_new(store, &binary); - if (!module) { - printf("> Error compiling module!\n"); - return 1; - } - + wasm_module_t* module = NULL; + error = wasmtime_module_new(store, &binary, &module); + if (error) + exit_with_error("failed to compile module", error, NULL); wasm_byte_vec_delete(&binary); // Instantiate. printf("Instantiating module...\n"); - wasm_instance_t* instance = wasm_instance_new(store, module, NULL, NULL); - if (!instance) { - printf("> Error instantiating module!\n"); - return 1; - } + wasm_instance_t* instance = NULL; + wasm_trap_t *trap = NULL; + error = wasmtime_instance_new(module, NULL, 0, &instance, &trap); + if (!instance) + exit_with_error("failed to instantiate", error, trap); // Extract export. printf("Extracting exports...\n"); @@ -246,3 +252,18 @@ int main(int argc, const char* argv[]) { printf("Done.\n"); return 0; } + +static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) { + fprintf(stderr, "error: %s\n", message); + wasm_byte_vec_t error_message; + if (error != NULL) { + wasmtime_error_message(error, &error_message); + wasmtime_error_delete(error); + } else { + wasm_trap_message(trap, &error_message); + wasm_trap_delete(trap); + } + fprintf(stderr, "%.*s\n", (int) error_message.size, error_message.data); + wasm_byte_vec_delete(&error_message); + exit(1); +} diff --git a/examples/multi.c b/examples/multi.c index 735964d561ae..dfc9eea9a00f 100644 --- a/examples/multi.c +++ b/examples/multi.c @@ -28,6 +28,8 @@ originally #include #include +static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap); + // A function to be called from Wasm code. wasm_trap_t* callback( const wasm_val_t args[], wasm_val_t results[] @@ -83,20 +85,18 @@ int main(int argc, const char* argv[]) { fclose(file); // Parse the wat into the binary wasm format - wasm_byte_vec_t binary, error; - if (wasmtime_wat2wasm(&wat, &binary, &error) == 0) { - fprintf(stderr, "failed to parse wat %.*s\n", (int) error.size, error.data); - return 1; - } + wasm_byte_vec_t binary; + wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &binary); + if (error != NULL) + exit_with_error("failed to parse wat", error, NULL); wasm_byte_vec_delete(&wat); // Compile. printf("Compiling module...\n"); - wasm_module_t* module = wasm_module_new(store, &binary); - if (!module) { - printf("> Error compiling module!\n"); - return 1; - } + wasm_module_t* module = NULL; + error = wasmtime_module_new(store, &binary, &module); + if (error) + exit_with_error("failed to compile module", error, NULL); wasm_byte_vec_delete(&binary); @@ -116,12 +116,11 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); const wasm_extern_t* imports[] = {wasm_func_as_extern(callback_func)}; - wasm_instance_t* instance = - wasm_instance_new(store, module, imports, NULL); - if (!instance) { - printf("> Error instantiating module!\n"); - return 1; - } + wasm_instance_t* instance = NULL; + wasm_trap_t* trap = NULL; + error = wasmtime_instance_new(module, imports, 1, &instance, &trap); + if (!instance) + exit_with_error("failed to instantiate", error, trap); wasm_func_delete(callback_func); @@ -133,7 +132,7 @@ int main(int argc, const char* argv[]) { printf("> Error accessing exports!\n"); return 1; } - const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]); + wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]); if (run_func == NULL) { printf("> Error accessing export!\n"); return 1; @@ -144,16 +143,15 @@ int main(int argc, const char* argv[]) { // Call. printf("Calling export...\n"); - wasm_val_t args[4]; + wasm_val_t args[2]; args[0].kind = WASM_I32; args[0].of.i32 = 1; args[1].kind = WASM_I64; args[1].of.i64 = 2; wasm_val_t results[2]; - if (wasm_func_call(run_func, args, results)) { - printf("> Error calling function!\n"); - return 1; - } + error = wasmtime_func_call(run_func, args, 2, results, 2, &trap); + if (error != NULL || trap != NULL) + exit_with_error("failed to call run", error, trap); wasm_extern_vec_delete(&exports); @@ -177,3 +175,17 @@ int main(int argc, const char* argv[]) { return 0; } +static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) { + fprintf(stderr, "error: %s\n", message); + wasm_byte_vec_t error_message; + if (error != NULL) { + wasmtime_error_message(error, &error_message); + wasmtime_error_delete(error); + } else { + wasm_trap_message(trap, &error_message); + wasm_trap_delete(trap); + } + fprintf(stderr, "%.*s\n", (int) error_message.size, error_message.data); + wasm_byte_vec_delete(&error_message); + exit(1); +} diff --git a/examples/wasi/main.c b/examples/wasi/main.c index 6e027025a3e2..1226f94ce21f 100644 --- a/examples/wasi/main.c +++ b/examples/wasi/main.c @@ -21,11 +21,11 @@ to tweak the `-lpthread` and such annotations. #include #include #include +#include #define MIN(a, b) ((a) < (b) ? (a) : (b)) -static void print_trap(wasm_trap_t *trap); -static void read_wat_file(wasm_engine_t *engine, wasm_byte_vec_t *bytes, const char *file); +static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap); int main() { int ret = 0; @@ -35,7 +35,6 @@ int main() { wasm_store_t *store = wasm_store_new(engine); assert(store != NULL); - wasm_byte_vec_t wasm; // Load our input file to parse it next FILE* file = fopen("target/wasm32-wasi/debug/wasi.wasm", "rb"); @@ -54,8 +53,10 @@ int main() { fclose(file); // Compile our modules - wasm_module_t *module = wasm_module_new(store, &wasm); - assert(module != NULL); + wasm_module_t *module = NULL; + wasmtime_error_t *error = wasmtime_module_new(store, &wasm, &module); + if (!module) + exit_with_error("failed to compile module", error, NULL); wasm_byte_vec_delete(&wasm); // Instantiate wasi @@ -68,10 +69,8 @@ int main() { wasi_config_inherit_stderr(wasi_config); wasm_trap_t *trap = NULL; wasi_instance_t *wasi = wasi_instance_new(store, "wasi_snapshot_preview1", wasi_config, &trap); - if (wasi == NULL) { - print_trap(trap); - exit(1); - } + if (wasi == NULL) + exit_with_error("failed to instantiate WASI", NULL, trap); // Create import list for our module using wasi wasm_importtype_vec_t import_types; @@ -87,15 +86,14 @@ int main() { exit(1); } } - wasm_importtype_vec_delete(&import_types); // Instantiate the module - wasm_instance_t *instance = wasm_instance_new(store, module, imports, &trap); - if (instance == NULL) { - print_trap(trap); - exit(1); - } + wasm_instance_t *instance = NULL; + error = wasmtime_instance_new(module, imports, import_types.size, &instance, &trap); + if (instance == NULL) + exit_with_error("failed to instantiate", error, trap); free(imports); + wasm_importtype_vec_delete(&import_types); // Lookup our `_start` export function wasm_extern_vec_t externs; @@ -111,11 +109,9 @@ int main() { assert(start_extern); wasm_func_t *start = wasm_extern_as_func(start_extern); assert(start != NULL); - trap = wasm_func_call(start, NULL, NULL); - if (trap != NULL) { - print_trap(trap); - exit(1); - } + error = wasmtime_func_call(start, NULL, 0, NULL, 0, &trap); + if (error != NULL || trap != NULL) + exit_with_error("failed to call `_start`", error, trap); // Clean up after ourselves at this point wasm_exporttype_vec_delete(&exports); @@ -127,12 +123,17 @@ int main() { return 0; } -static void print_trap(wasm_trap_t *trap) { - assert(trap != NULL); - wasm_message_t message; - wasm_trap_message(trap, &message); - fprintf(stderr, "failed to instantiate module %.*s\n", (int) message.size, message.data); - wasm_byte_vec_delete(&message); - wasm_trap_delete(trap); +static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) { + fprintf(stderr, "error: %s\n", message); + wasm_byte_vec_t error_message; + if (error != NULL) { + wasmtime_error_message(error, &error_message); + wasmtime_error_delete(error); + } else { + wasm_trap_message(trap, &error_message); + wasm_trap_delete(trap); + } + fprintf(stderr, "%.*s\n", (int) error_message.size, error_message.data); + wasm_byte_vec_delete(&error_message); + exit(1); } - diff --git a/tests/custom_signal_handler.rs b/tests/custom_signal_handler.rs index 85f9af365166..27d14fc910a5 100644 --- a/tests/custom_signal_handler.rs +++ b/tests/custom_signal_handler.rs @@ -37,7 +37,7 @@ mod tests { ) "#; - fn invoke_export(instance: &Instance, func_name: &str) -> Result, Trap> { + fn invoke_export(instance: &Instance, func_name: &str) -> Result> { let ret = instance .get_export(func_name) .unwrap() @@ -117,7 +117,9 @@ mod tests { { println!("calling read_out_of_bounds..."); - let trap = invoke_export(&instance, "read_out_of_bounds").unwrap_err(); + let trap = invoke_export(&instance, "read_out_of_bounds") + .unwrap_err() + .downcast::()?; assert!( trap.message() .starts_with("wasm trap: out of bounds memory access"), @@ -141,7 +143,10 @@ mod tests { .func() .expect("expected a 'read_out_of_bounds' func in the module"); println!("calling read_out_of_bounds..."); - let trap = read_out_of_bounds_func.call(&[]).unwrap_err(); + let trap = read_out_of_bounds_func + .call(&[]) + .unwrap_err() + .downcast::()?; assert!(trap .message() .starts_with("wasm trap: out of bounds memory access"));