From 3b39b9226cd1c557225717f2a42f64a49d2d730e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 3 Apr 2020 11:04:25 -0700 Subject: [PATCH 1/8] Add Wasmtime-specific C API functions to return errors This commit adds new `wasmtime_*` symbols to the C API, many of which mirror the existing counterparts in the `wasm.h` header. These APIs are enhanced in a number of respects: * Detailed error information is now available through a `wasmtime_error_t`. Currently this only exposes one function which is to extract a string version of the error. * There is a distinction now between traps and errors during instantiation and function calling. Traps only happen if wasm traps, and errors can happen for things like runtime type errors when interacting with the API. * APIs have improved safety with respect to embedders where the lengths of arrays are now taken as explicit parameters rather than assumed from other parameters. --- RELEASES.md | 23 ++++++ crates/api/src/func.rs | 16 ++-- crates/c-api/include/wasmtime.h | 133 +++++++++++++++++++++++++++----- crates/c-api/src/config.rs | 29 ++++--- crates/c-api/src/error.rs | 46 +++++++++++ crates/c-api/src/func.rs | 78 ++++++++++++++----- crates/c-api/src/global.rs | 42 ++++++++-- crates/c-api/src/instance.rs | 126 +++++++++++++++++++++--------- crates/c-api/src/lib.rs | 2 + crates/c-api/src/linker.rs | 32 ++++---- crates/c-api/src/module.rs | 62 +++++++++++---- crates/c-api/src/trap.rs | 6 ++ crates/c-api/src/wat2wasm.rs | 27 ++----- 13 files changed, 464 insertions(+), 158 deletions(-) create mode 100644 crates/c-api/src/error.rs 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/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()) + }) } From 3df40bc554301e06a6b0d8aaf7ddd50e8e92d6fe Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 3 Apr 2020 15:03:53 -0700 Subject: [PATCH 2/8] Handle trap updates --- crates/api/tests/func.rs | 7 ++--- crates/api/tests/import_calling_export.rs | 14 ++++++---- crates/api/tests/traps.rs | 32 ++++++++++++++++++----- crates/wast/src/wast.rs | 2 +- tests/custom_signal_handler.rs | 11 +++++--- 5 files changed, 48 insertions(+), 18 deletions(-) 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..83126f57c737 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,16 +331,20 @@ 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().downcast::()?.message(), "expected 1 arguments, got 0" ); assert_eq!( - func.call(&[Val::F32(0)]).unwrap_err().message(), + func.call(&[Val::F32(0)]) + .unwrap_err() + .downcast::()? + .message(), "argument type mismatch", ); assert_eq!( func.call(&[Val::I32(0), Val::I32(1)]) .unwrap_err() + .downcast::()? .message(), "expected 1 arguments, got 2" ); 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/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")); From 45a558cab4e581e506d1ee269ffe246c5e251733 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Apr 2020 07:47:09 -0700 Subject: [PATCH 3/8] Update C examples --- crates/fuzzing/src/oracles.rs | 2 +- examples/fib-debug/main.c | 39 ++++++++++----- examples/gcd.c | 55 ++++++++++----------- examples/hello.c | 58 +++++++++++----------- examples/linking.c | 93 +++++++++++++++++------------------ examples/memory.c | 86 +++++++++++++++++++------------- examples/multi.c | 56 ++++++++++++--------- examples/wasi/main.c | 57 ++++++++++----------- 8 files changed, 245 insertions(+), 201 deletions(-) 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/examples/fib-debug/main.c b/examples/fib-debug/main.c index 95960ab44cce..b611212dbc2c 100644 --- a/examples/fib-debug/main.c +++ b/examples/fib-debug/main.c @@ -8,6 +8,8 @@ #define own +static void print_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,10 +42,10 @@ int main(int argc, const char* argv[]) { // Compile. printf("Compiling module...\n"); - own wasm_module_t* module = wasm_module_new(store, &binary); + wasm_module_t *module = NULL; + wasmtime_error_t* error = wasmtime_module_new(store, &binary, &module); if (!module) { - printf("> Error compiling module!\n"); - return 1; + print_error("failed to compile module", error, NULL); } wasm_byte_vec_delete(&binary); @@ -68,12 +70,13 @@ 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) { + print_error("failed to instantiate", error, trap); } + wasm_module_delete(module); // Extract export. printf("Extracting export...\n"); @@ -84,21 +87,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"); + error = wasmtime_func_call(run_func, params, 1, results, 1, &trap); + if (error != NULL || trap != NULL) { + print_error("failed to call function", error, trap); return 1; } @@ -116,3 +119,15 @@ int main(int argc, const char* argv[]) { return 0; } +static void print_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..8dbc130f9a4b 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 print_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) + print_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) + print_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) + print_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) + print_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 print_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..1e3b7e105318 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 print_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) + print_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) + print_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) + print_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) + print_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 print_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..36252c8f21d1 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 print_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) + print_error("failed to compile linking1", error, NULL); + error = wasmtime_module_new(store, &linking2_wasm, &linking2_module); + if (error != NULL) + print_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) + print_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) + print_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) + print_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) + print_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) + print_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) + print_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) + print_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 print_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..2f8dbf3efab8 100644 --- a/examples/memory.c +++ b/examples/memory.c @@ -28,6 +28,7 @@ originally #include #include +static void print_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) + print_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) + print_error("failed to call function", error, trap); } void check_ok2(wasm_func_t* func, int32_t arg1, int32_t arg2) { @@ -90,13 +95,16 @@ 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[]) { - wasm_val_t results[1]; - wasm_trap_t* trap = wasm_func_call(func, args, results); - if (! trap) { +void check_trap(wasm_func_t* func, wasm_val_t args[], size_t num_args, size_t num_results) { + wasm_val_t results[num_results]; + wasm_trap_t *trap = NULL; + wasmtime_error_t *error = wasmtime_func_call(func, args, num_args, results, num_results, &trap); + if (error != NULL) + print_error("failed to call function", error, NULL); + if (trap == NULL) { printf("> Error on result, expected trap\n"); exit(1); } @@ -105,7 +113,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 +121,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 +148,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) + print_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) + print_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) + print_error("failed to instantiate", error, trap); // Extract export. printf("Extracting exports...\n"); @@ -246,3 +251,18 @@ int main(int argc, const char* argv[]) { printf("Done.\n"); return 0; } + +static void print_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..c489c2af3756 100644 --- a/examples/multi.c +++ b/examples/multi.c @@ -28,6 +28,8 @@ originally #include #include +static void print_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) + print_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) + print_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) + print_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) + print_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 print_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..6ee401882e45 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 print_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) + print_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) + print_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) + print_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) + print_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 print_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); } - From de089d022f4c1d62304171638044a9175347b43c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Apr 2020 07:56:48 -0700 Subject: [PATCH 4/8] Fix memory.c compile on MSVC --- examples/memory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/memory.c b/examples/memory.c index 2f8dbf3efab8..5ef0756582a1 100644 --- a/examples/memory.c +++ b/examples/memory.c @@ -99,7 +99,8 @@ void check_ok2(wasm_func_t* func, int32_t arg1, int32_t arg2) { } void check_trap(wasm_func_t* func, wasm_val_t args[], size_t num_args, size_t num_results) { - wasm_val_t results[num_results]; + wasm_val_t results[1]; + 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) From 263683f0aeb965c78be776aa7eb1af04e6d82703 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Apr 2020 09:05:21 -0700 Subject: [PATCH 5/8] Update test assertions --- crates/api/tests/traps.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/crates/api/tests/traps.rs b/crates/api/tests/traps.rs index 83126f57c737..e76f6a3dcd80 100644 --- a/crates/api/tests/traps.rs +++ b/crates/api/tests/traps.rs @@ -331,21 +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().downcast::()?.message(), + func.call(&[]).unwrap_err().to_string(), "expected 1 arguments, got 0" ); assert_eq!( - func.call(&[Val::F32(0)]) - .unwrap_err() - .downcast::()? - .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() - .downcast::()? - .message(), + .to_string(), "expected 1 arguments, got 2" ); Ok(()) From 64347194f43173f17e968545f7fda11bb95dc653 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Apr 2020 11:35:47 -0700 Subject: [PATCH 6/8] Refactor C slightly --- examples/fib-debug/main.c | 20 ++++++++------------ examples/gcd.c | 12 ++++++------ examples/hello.c | 12 ++++++------ examples/linking.c | 22 +++++++++++----------- examples/memory.c | 16 ++++++++-------- examples/multi.c | 12 ++++++------ examples/wasi/main.c | 12 ++++++------ 7 files changed, 51 insertions(+), 55 deletions(-) diff --git a/examples/fib-debug/main.c b/examples/fib-debug/main.c index b611212dbc2c..dfebf8993e4c 100644 --- a/examples/fib-debug/main.c +++ b/examples/fib-debug/main.c @@ -8,7 +8,7 @@ #define own -static void print_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap); +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. @@ -44,9 +44,8 @@ int main(int argc, const char* argv[]) { printf("Compiling module...\n"); wasm_module_t *module = NULL; wasmtime_error_t* error = wasmtime_module_new(store, &binary, &module); - if (!module) { - print_error("failed to compile module", error, NULL); - } + if (!module) + exit_with_error("failed to compile module", error, NULL); wasm_byte_vec_delete(&binary); // Figure out which export is the `fib` export @@ -73,9 +72,8 @@ int main(int argc, const char* argv[]) { wasm_instance_t* instance = NULL; wasm_trap_t *trap = NULL; error = wasmtime_instance_new(module, NULL, 0, &instance, &trap); - if (error != NULL || trap != NULL) { - print_error("failed to instantiate", error, trap); - } + if (error != NULL || trap != NULL) + exit_with_error("failed to instantiate", error, trap); wasm_module_delete(module); // Extract export. @@ -100,10 +98,8 @@ int main(int argc, const char* argv[]) { wasm_val_t params[1] = { {.kind = WASM_I32, .of = {.i32 = 6}} }; wasm_val_t results[1]; error = wasmtime_func_call(run_func, params, 1, results, 1, &trap); - if (error != NULL || trap != NULL) { - print_error("failed to call function", error, trap); - return 1; - } + if (error != NULL || trap != NULL) + exit_with_error("failed to call function", error, trap); wasm_extern_vec_delete(&exports); @@ -119,7 +115,7 @@ int main(int argc, const char* argv[]) { return 0; } -static void print_error(const char *message, wasmtime_error_t *error, wasm_trap_t *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) { diff --git a/examples/gcd.c b/examples/gcd.c index 8dbc130f9a4b..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_error(const char *message, wasmtime_error_t *error, 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; @@ -54,20 +54,20 @@ int main() { wasm_byte_vec_t wasm; wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &wasm); if (error != NULL) - print_error("failed to parse wat", 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 = NULL; error = wasmtime_module_new(store, &wasm, &module); if (module == NULL) - print_error("failed to compile module", error, NULL); + exit_with_error("failed to compile module", error, NULL); wasm_byte_vec_delete(&wasm); wasm_trap_t *trap = NULL; wasm_instance_t *instance = NULL; error = wasmtime_instance_new(module, NULL, 0, &instance, &trap); if (instance == NULL) - print_error("failed to instantiate", error, trap); + exit_with_error("failed to instantiate", error, trap); // Lookup our `gcd` export function wasm_extern_vec_t externs; @@ -87,7 +87,7 @@ int main() { params[1].of.i32 = b; error = wasmtime_func_call(gcd, params, 2, results, 1, &trap); if (error != NULL || trap != NULL) - print_error("failed to call gcd", error, trap); + 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); @@ -103,7 +103,7 @@ int main() { return ret; } -static void print_error(const char *message, wasmtime_error_t *error, wasm_trap_t *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) { diff --git a/examples/hello.c b/examples/hello.c index 1e3b7e105318..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_error(const char *message, wasmtime_error_t *error, 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"); @@ -61,7 +61,7 @@ int main() { wasm_byte_vec_t wasm; wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &wasm); if (error != NULL) - print_error("failed to parse wat", 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. @@ -70,7 +70,7 @@ int main() { error = wasmtime_module_new(store, &wasm, &module); wasm_byte_vec_delete(&wasm); if (error != NULL) - print_error("failed to compile module", 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 @@ -89,7 +89,7 @@ int main() { const wasm_extern_t *imports[] = { wasm_func_as_extern(hello) }; error = wasmtime_instance_new(module, imports, 1, &instance, &trap); if (instance == NULL) - print_error("failed to instantiate", error, trap); + exit_with_error("failed to instantiate", error, trap); // Lookup our `run` export function printf("Extracting export...\n"); @@ -103,7 +103,7 @@ int main() { printf("Calling export...\n"); error = wasmtime_func_call(run, NULL, 0, NULL, 0, &trap); if (error != NULL || trap != NULL) - print_error("failed to call function", error, trap); + exit_with_error("failed to call function", error, trap); // Clean up after ourselves at this point printf("All finished!\n"); @@ -117,7 +117,7 @@ int main() { return ret; } -static void print_error(const char *message, wasmtime_error_t *error, wasm_trap_t *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) { diff --git a/examples/linking.c b/examples/linking.c index 36252c8f21d1..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_error(const char *message, wasmtime_error_t *error, 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() { @@ -47,10 +47,10 @@ int main() { wasm_module_t *linking2_module = NULL; error = wasmtime_module_new(store, &linking1_wasm, &linking1_module); if (error != NULL) - print_error("failed to compile linking1", error, NULL); + exit_with_error("failed to compile linking1", error, NULL); error = wasmtime_module_new(store, &linking2_wasm, &linking2_module); if (error != NULL) - print_error("failed to compile linking2", error, NULL); + exit_with_error("failed to compile linking2", error, NULL); wasm_byte_vec_delete(&linking1_wasm); wasm_byte_vec_delete(&linking2_wasm); @@ -65,20 +65,20 @@ int main() { wasm_trap_t *trap = NULL; wasi_instance_t *wasi = wasi_instance_new(store, "wasi_snapshot_preview1", wasi_config, &trap); if (wasi == NULL) - print_error("failed to instantiate wasi", NULL, trap); + 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); error = wasmtime_linker_define_wasi(linker, wasi); if (error != NULL) - print_error("failed to link wasi", error, NULL); + exit_with_error("failed to link wasi", error, NULL); // Instantiate `linking2` with our linker. wasm_instance_t *linking2; error = wasmtime_linker_instantiate(linker, linking2_module, &linking2, &trap); if (error != NULL || trap != NULL) - print_error("failed to instantiate linking2", error, trap); + exit_with_error("failed to instantiate linking2", error, trap); // Register our new `linking2` instance with the linker wasm_name_t linking2_name; @@ -86,13 +86,13 @@ int main() { linking2_name.size = strlen(linking2_name.data); error = wasmtime_linker_define_instance(linker, &linking2_name, linking2); if (error != NULL) - print_error("failed to link linking2", 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; error = wasmtime_linker_instantiate(linker, linking1_module, &linking1, &trap); if (error != NULL || trap != NULL) - print_error("failed to instantiate linking1", error, trap); + exit_with_error("failed to instantiate linking1", error, trap); // Lookup our `run` export function wasm_extern_vec_t linking1_externs; @@ -102,7 +102,7 @@ int main() { assert(run != NULL); error = wasmtime_func_call(run, NULL, 0, NULL, 0, &trap); if (error != NULL || trap != NULL) - print_error("failed to call run", error, trap); + exit_with_error("failed to call run", error, trap); // Clean up after ourselves at this point wasm_extern_vec_delete(&linking1_externs); @@ -141,11 +141,11 @@ static void read_wat_file( // Parse the wat into the binary wasm format wasmtime_error_t *error = wasmtime_wat2wasm(&wat, bytes); if (error != NULL) - print_error("failed to parse wat", error, NULL); + exit_with_error("failed to parse wat", error, NULL); wasm_byte_vec_delete(&wat); } -static void print_error(const char *message, wasmtime_error_t *error, wasm_trap_t *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) { diff --git a/examples/memory.c b/examples/memory.c index 5ef0756582a1..1687048f9254 100644 --- a/examples/memory.c +++ b/examples/memory.c @@ -28,7 +28,7 @@ originally #include #include -static void print_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap); +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])) { @@ -59,7 +59,7 @@ void check_call(wasm_func_t* func, wasm_val_t args[], size_t num_args, int32_t e wasm_trap_t *trap = NULL; wasmtime_error_t *error = wasmtime_func_call(func, args, num_args, results, 1, &trap); if (error != NULL || trap != NULL) - print_error("failed to call function", error, trap); + exit_with_error("failed to call function", error, trap); if (results[0].of.i32 != expected) { printf("> Error on result\n"); exit(1); @@ -87,7 +87,7 @@ 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) - print_error("failed to call function", error, trap); + exit_with_error("failed to call function", error, trap); } void check_ok2(wasm_func_t* func, int32_t arg1, int32_t arg2) { @@ -104,7 +104,7 @@ void check_trap(wasm_func_t* func, wasm_val_t args[], size_t num_args, size_t nu wasm_trap_t *trap = NULL; wasmtime_error_t *error = wasmtime_func_call(func, args, num_args, results, num_results, &trap); if (error != NULL) - print_error("failed to call function", error, NULL); + exit_with_error("failed to call function", error, NULL); if (trap == NULL) { printf("> Error on result, expected trap\n"); exit(1); @@ -152,7 +152,7 @@ int main(int argc, const char* argv[]) { wasm_byte_vec_t binary; wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &binary); if (error != NULL) - print_error("failed to parse wat", error, NULL); + exit_with_error("failed to parse wat", error, NULL); wasm_byte_vec_delete(&wat); // Compile. @@ -160,7 +160,7 @@ int main(int argc, const char* argv[]) { wasm_module_t* module = NULL; error = wasmtime_module_new(store, &binary, &module); if (error) - print_error("failed to compile module", error, NULL); + exit_with_error("failed to compile module", error, NULL); wasm_byte_vec_delete(&binary); // Instantiate. @@ -169,7 +169,7 @@ int main(int argc, const char* argv[]) { wasm_trap_t *trap = NULL; error = wasmtime_instance_new(module, NULL, 0, &instance, &trap); if (!instance) - print_error("failed to instantiate", error, trap); + exit_with_error("failed to instantiate", error, trap); // Extract export. printf("Extracting exports...\n"); @@ -253,7 +253,7 @@ int main(int argc, const char* argv[]) { return 0; } -static void print_error(const char *message, wasmtime_error_t *error, wasm_trap_t *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) { diff --git a/examples/multi.c b/examples/multi.c index c489c2af3756..dfc9eea9a00f 100644 --- a/examples/multi.c +++ b/examples/multi.c @@ -28,7 +28,7 @@ originally #include #include -static void print_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap); +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( @@ -88,7 +88,7 @@ int main(int argc, const char* argv[]) { wasm_byte_vec_t binary; wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &binary); if (error != NULL) - print_error("failed to parse wat", error, NULL); + exit_with_error("failed to parse wat", error, NULL); wasm_byte_vec_delete(&wat); // Compile. @@ -96,7 +96,7 @@ int main(int argc, const char* argv[]) { wasm_module_t* module = NULL; error = wasmtime_module_new(store, &binary, &module); if (error) - print_error("failed to compile module", error, NULL); + exit_with_error("failed to compile module", error, NULL); wasm_byte_vec_delete(&binary); @@ -120,7 +120,7 @@ int main(int argc, const char* argv[]) { wasm_trap_t* trap = NULL; error = wasmtime_instance_new(module, imports, 1, &instance, &trap); if (!instance) - print_error("failed to instantiate", error, trap); + exit_with_error("failed to instantiate", error, trap); wasm_func_delete(callback_func); @@ -151,7 +151,7 @@ int main(int argc, const char* argv[]) { wasm_val_t results[2]; error = wasmtime_func_call(run_func, args, 2, results, 2, &trap); if (error != NULL || trap != NULL) - print_error("failed to call run", error, trap); + exit_with_error("failed to call run", error, trap); wasm_extern_vec_delete(&exports); @@ -175,7 +175,7 @@ int main(int argc, const char* argv[]) { return 0; } -static void print_error(const char *message, wasmtime_error_t *error, wasm_trap_t *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) { diff --git a/examples/wasi/main.c b/examples/wasi/main.c index 6ee401882e45..1226f94ce21f 100644 --- a/examples/wasi/main.c +++ b/examples/wasi/main.c @@ -25,7 +25,7 @@ to tweak the `-lpthread` and such annotations. #define MIN(a, b) ((a) < (b) ? (a) : (b)) -static void print_error(const char *message, wasmtime_error_t *error, 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; @@ -56,7 +56,7 @@ int main() { wasm_module_t *module = NULL; wasmtime_error_t *error = wasmtime_module_new(store, &wasm, &module); if (!module) - print_error("failed to compile module", error, NULL); + exit_with_error("failed to compile module", error, NULL); wasm_byte_vec_delete(&wasm); // Instantiate wasi @@ -70,7 +70,7 @@ int main() { wasm_trap_t *trap = NULL; wasi_instance_t *wasi = wasi_instance_new(store, "wasi_snapshot_preview1", wasi_config, &trap); if (wasi == NULL) - print_error("failed to instantiate WASI", NULL, trap); + exit_with_error("failed to instantiate WASI", NULL, trap); // Create import list for our module using wasi wasm_importtype_vec_t import_types; @@ -91,7 +91,7 @@ int main() { wasm_instance_t *instance = NULL; error = wasmtime_instance_new(module, imports, import_types.size, &instance, &trap); if (instance == NULL) - print_error("failed to instantiate", error, trap); + exit_with_error("failed to instantiate", error, trap); free(imports); wasm_importtype_vec_delete(&import_types); @@ -111,7 +111,7 @@ int main() { assert(start != NULL); error = wasmtime_func_call(start, NULL, 0, NULL, 0, &trap); if (error != NULL || trap != NULL) - print_error("failed to call `_start`", error, trap); + exit_with_error("failed to call `_start`", error, trap); // Clean up after ourselves at this point wasm_exporttype_vec_delete(&exports); @@ -123,7 +123,7 @@ int main() { return 0; } -static void print_error(const char *message, wasmtime_error_t *error, wasm_trap_t *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) { From 5006701c7800aa7c2bfece996306bb880b7d486d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Apr 2020 12:14:20 -0700 Subject: [PATCH 7/8] Bare-bones .NET update --- crates/misc/dotnet/src/Host.cs | 19 +++++----- crates/misc/dotnet/src/Instance.cs | 7 +++- crates/misc/dotnet/src/Interop.cs | 39 +++++++++++++++------ crates/misc/dotnet/src/WasmtimeException.cs | 23 ++++++++++++ 4 files changed, 68 insertions(+), 20 deletions(-) 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..e61b3f41ae1f 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,27 @@ 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)); + + int indexOfNull = byteSpan.LastIndexOf((byte)0); + if (indexOfNull != -1) + { + byteSpan = byteSpan.Slice(0, indexOfNull); + } + + var message = Encoding.UTF8.GetString(byteSpan); + Interop.wasm_byte_vec_delete(ref bytes); + + Interop.wasmtime_error_delete(error); + + return new WasmtimeException(message); + } + } } } From da931cad03c2b8cc1f12ff6f329709040c2963cc Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Apr 2020 13:12:44 -0700 Subject: [PATCH 8/8] Remove bogus nul handling --- crates/misc/dotnet/src/WasmtimeException.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/crates/misc/dotnet/src/WasmtimeException.cs b/crates/misc/dotnet/src/WasmtimeException.cs index e61b3f41ae1f..7494a5264c1b 100644 --- a/crates/misc/dotnet/src/WasmtimeException.cs +++ b/crates/misc/dotnet/src/WasmtimeException.cs @@ -28,13 +28,6 @@ internal static WasmtimeException FromOwnedError(IntPtr error) { Interop.wasmtime_error_message(error, out var bytes); var byteSpan = new ReadOnlySpan(bytes.data, checked((int)bytes.size)); - - int indexOfNull = byteSpan.LastIndexOf((byte)0); - if (indexOfNull != -1) - { - byteSpan = byteSpan.Slice(0, indexOfNull); - } - var message = Encoding.UTF8.GetString(byteSpan); Interop.wasm_byte_vec_delete(ref bytes);