From ed9134af86c4dd92849495fbb62c06a9ff8f421d Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 14 Jul 2021 18:54:14 -0700 Subject: [PATCH] Improved traps # Conflicts: # lib/js-api/tests/instance.rs --- lib/js-api/src/trap.rs | 28 ++++++++++-- lib/js-api/tests/instance.rs | 87 ++++++++++++++++++++++++++++-------- 2 files changed, 92 insertions(+), 23 deletions(-) diff --git a/lib/js-api/src/trap.rs b/lib/js-api/src/trap.rs index 6ce7ba58c..cdb07377f 100644 --- a/lib/js-api/src/trap.rs +++ b/lib/js-api/src/trap.rs @@ -10,10 +10,16 @@ use wasm_bindgen::JsValue; /// indicating the cause. #[wasm_bindgen] #[derive(Clone)] -pub struct RuntimeError { +pub struct WasmerRuntimeError { inner: Arc, } +/// This type is the same as `WasmerRuntimeError`. +/// +/// We use the `WasmerRuntimeError` name to not collide with the +/// `RuntimeError` in JS. +pub type RuntimeError = WasmerRuntimeError; + impl PartialEq for RuntimeError { fn eq(&self, other: &Self) -> bool { Arc::ptr_eq(&self.inner, &other.inner) @@ -56,6 +62,13 @@ impl RuntimeError { } } + /// Creates a new user `RuntimeError` with the given `error`. + pub fn user(error: impl Error + 'static) -> Self { + RuntimeError { + inner: Arc::new(RuntimeErrorSource::User(Box::new(error))), + } + } + /// Raises a custom user Error pub fn raise(error: Box) -> ! { let error = if error.is::() { @@ -127,9 +140,16 @@ pub fn generic_of_jsval>( let ctor_name = Object::get_prototype_of(&js).constructor().name(); if ctor_name == classname { let ptr = Reflect::get(&js, &JsValue::from_str("ptr"))?; - let ptr_u32: u32 = ptr.as_f64().ok_or(JsValue::NULL)? as u32; - let foo = unsafe { T::from_abi(ptr_u32) }; - Ok(foo) + match ptr.as_f64() { + Some(ptr_f64) => { + let foo = unsafe { T::from_abi(ptr_f64 as u32) }; + Ok(foo) + } + None => { + // We simply relay the js value + Err(js) + } + } } else { Err(js) } diff --git a/lib/js-api/tests/instance.rs b/lib/js-api/tests/instance.rs index 14c09e080..a576d9c7f 100644 --- a/lib/js-api/tests/instance.rs +++ b/lib/js-api/tests/instance.rs @@ -586,6 +586,49 @@ fn test_native_function() { assert_eq!(add_one.call(1), Ok(2)); } +#[wasm_bindgen_test] +fn test_panic() { + let store = Store::default(); + let module = Module::new( + &store, + br#" +(module + (type $run_t (func (param i32 i32) (result i32))) + (type $early_exit_t (func (param) (result))) + (import "env" "early_exit" (func $early_exit (type $early_exit_t))) + (func $run (type $run_t) (param $x i32) (param $y i32) (result i32) + (call $early_exit) + (i32.add + local.get $x + local.get $y)) + (export "run" (func $run))) +"#, + ) + .unwrap(); + + fn early_exit() { + panic!("Do panic") + } + + let import_object = imports! { + "env" => { + "early_exit" => Function::new_native(&store, early_exit), + } + }; + let instance = Instance::new(&module, &import_object).unwrap(); + + let run_func: NativeFunc<(i32, i32), i32> = + instance.exports.get_native_function("run").unwrap(); + + assert!(run_func.call(1, 7).is_err(), "Expected early termination",); + let run_func = instance.exports.get_function("run").unwrap(); + + assert!( + run_func.call(&[Val::I32(1), Val::I32(7)]).is_err(), + "Expected early termination", + ); +} + #[wasm_bindgen_test] fn test_custom_error() { let store = Store::default(); @@ -630,27 +673,33 @@ fn test_custom_error() { }; let instance = Instance::new(&module, &import_object).unwrap(); - let run_func: NativeFunc<(i32, i32), i32> = - instance.exports.get_native_function("run").unwrap(); - - match run_func.call(1, 7) { - Ok(result) => { - assert!( - false, - "Expected early termination with `ExitCode`, found: {}", - result - ); - } - Err(e) => { - match e.downcast::() { - // We found the exit code used to terminate execution. - Ok(exit_code) => { - assert_eq!(exit_code.0, 1); - } - Err(e) => { - assert!(false, "Unknown error `{:?}` found. expected `ErrorCode`", e); + fn test_result(result: Result) { + match result { + Ok(result) => { + assert!( + false, + "Expected early termination with `ExitCode`, found: {:?}", + result + ); + } + Err(e) => { + match e.downcast::() { + // We found the exit code used to terminate execution. + Ok(exit_code) => { + assert_eq!(exit_code.0, 1); + } + Err(e) => { + assert!(false, "Unknown error `{:?}` found. expected `ErrorCode`", e); + } } } } } + + let run_func: NativeFunc<(i32, i32), i32> = + instance.exports.get_native_function("run").unwrap(); + test_result(run_func.call(1, 7)); + + let run_func = instance.exports.get_function("run").unwrap(); + test_result(run_func.call(&[Val::I32(1), Val::I32(7)])); }