From 559d529ece35d9cb18c5c8b99ba09c29bad3d3e7 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 23 Jan 2018 14:05:31 +0300 Subject: [PATCH 1/4] initial layout --- src/host.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/host.rs b/src/host.rs index ab686ef..bcfdb7e 100644 --- a/src/host.rs +++ b/src/host.rs @@ -2,6 +2,20 @@ use std::any::TypeId; use value::RuntimeValue; use Error; +pub struct RuntimeArgs<'a>(&'a [RuntimeValue]); + +impl<'a> From<&'a [RuntimeValue]> for RuntimeArgs<'a> { + fn from(inner: &'a [RuntimeValue]) -> Self { + RuntimeArgs(inner) + } +} + +impl<'a> RuntimeArgs<'a> { + fn nth(&self, idx: usize) -> Result where RuntimeValue: From { + Err(Error::Value("Invalid cast".to_owned())) + } +} + /// Custom user error. pub trait HostError: 'static + ::std::fmt::Display + ::std::fmt::Debug { #[doc(hidden)] @@ -50,3 +64,18 @@ impl Externals for NopExternals { Err(Error::Trap("invoke index on no-op externals".into())) } } + +#[cfg(test)] +mod tests { + + use value::RuntimeValue; + use super::RuntimeArgs; + + #[test] + fn i32_runtime_args() { + let args: RuntimeArgs = (&[RuntimeValue::I32(0)][..]).into(); + let val: i32 = args.nth(0).unwrap(); + assert_eq!(val, 0); + } + +} \ No newline at end of file From 4eb8608c1e75efad314ffd616410c9267da3dc56 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 23 Jan 2018 14:26:45 +0300 Subject: [PATCH 2/4] rewire everything --- examples/tictactoe.rs | 9 +++++---- src/func.rs | 4 ++-- src/host.rs | 26 +++++++++++++++++++++----- src/lib.rs | 2 +- src/tests/host.rs | 25 ++++++++++++------------- 5 files changed, 41 insertions(+), 25 deletions(-) diff --git a/examples/tictactoe.rs b/examples/tictactoe.rs index 76760fc..203d185 100644 --- a/examples/tictactoe.rs +++ b/examples/tictactoe.rs @@ -6,8 +6,9 @@ use std::fmt; use std::fs::File; use wasmi::{ Error as InterpreterError, ModuleInstance, ModuleRef, - Externals, RuntimeValue, FuncRef, TryInto, ModuleImportResolver, + Externals, RuntimeValue, FuncRef, ModuleImportResolver, FuncInstance, HostError, ImportsBuilder, Signature, ValueType, + RuntimeArgs, }; #[derive(Debug)] @@ -147,16 +148,16 @@ impl<'a> Externals for Runtime<'a> { fn invoke_index( &mut self, index: usize, - args: &[RuntimeValue], + args: RuntimeArgs, ) -> Result, InterpreterError> { match index { SET_FUNC_INDEX => { - let idx: i32 = args[0].try_into().unwrap(); + let idx: i32 = args.nth(0)?; self.game.set(idx, self.player)?; Ok(None) } GET_FUNC_INDEX => { - let idx: i32 = args[0].try_into().unwrap(); + let idx: i32 = args.nth(0)?; let val: i32 = tictactoe::Player::into_i32(self.game.get(idx)?); Ok(Some(val.into())) } diff --git a/src/func.rs b/src/func.rs index 7e1c443..7370124 100644 --- a/src/func.rs +++ b/src/func.rs @@ -43,7 +43,7 @@ impl fmt::Debug for FuncInstance { ref signature, .. } => { - // We can't write description of self.module here, because it generate + // We can't write description of self.module here, because it generate // debug string for function instances and this will lead to infinite loop. write!( f, @@ -132,7 +132,7 @@ impl FuncInstance { let mut interpreter = Interpreter::new(externals); interpreter.run_function(ctx) } - InvokeKind::Host(host_func, args) => externals.invoke_index(host_func, args), + InvokeKind::Host(host_func, args) => externals.invoke_index(host_func, args.into()), } } } diff --git a/src/host.rs b/src/host.rs index bcfdb7e..4557f40 100644 --- a/src/host.rs +++ b/src/host.rs @@ -1,7 +1,8 @@ use std::any::TypeId; -use value::RuntimeValue; +use value::{RuntimeValue, TryInto}; use Error; +/// Safe wrapper for list of arguments pub struct RuntimeArgs<'a>(&'a [RuntimeValue]); impl<'a> From<&'a [RuntimeValue]> for RuntimeArgs<'a> { @@ -11,8 +12,23 @@ impl<'a> From<&'a [RuntimeValue]> for RuntimeArgs<'a> { } impl<'a> RuntimeArgs<'a> { - fn nth(&self, idx: usize) -> Result where RuntimeValue: From { - Err(Error::Value("Invalid cast".to_owned())) + + /// Extract argument by index `idx` returning error if cast is invalid or not enough arguments + pub fn nth(&self, idx: usize) -> Result where RuntimeValue: TryInto { + Ok(self.nth_value(idx)?.try_into().map_err(|_| Error::Value("Invalid argument cast".to_owned()))?) + } + + /// Extract argument as a runtime value by index `idx` returning error is not enougn arguments + pub fn nth_value(&self, idx: usize) -> Result { + if self.0.len() <= idx { + return Err(Error::Value("Invalid argument index".to_owned())); + } + Ok(self.0[idx]) + } + + /// Total number of arguments + pub fn len(&self) -> usize { + self.0.len() } } @@ -49,7 +65,7 @@ pub trait Externals { fn invoke_index( &mut self, index: usize, - args: &[RuntimeValue], + args: RuntimeArgs, ) -> Result, Error>; } @@ -59,7 +75,7 @@ impl Externals for NopExternals { fn invoke_index( &mut self, _index: usize, - _args: &[RuntimeValue], + _args: RuntimeArgs, ) -> Result, Error> { Err(Error::Trap("invoke index on no-op externals".into())) } diff --git a/src/lib.rs b/src/lib.rs index 3523d49..d763009 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -130,7 +130,7 @@ mod tests; pub use self::memory::{MemoryInstance, MemoryRef}; pub use self::table::{TableInstance, TableRef}; pub use self::value::{RuntimeValue, TryInto}; -pub use self::host::{Externals, NopExternals, HostError}; +pub use self::host::{Externals, NopExternals, HostError, RuntimeArgs}; pub use self::imports::{ModuleImportResolver, ImportResolver, ImportsBuilder}; pub use self::module::{ModuleInstance, ModuleRef, ExternVal, NotStartedModuleRef}; pub use self::global::{GlobalInstance, GlobalRef}; diff --git a/src/tests/host.rs b/src/tests/host.rs index c96a2d9..96570f3 100644 --- a/src/tests/host.rs +++ b/src/tests/host.rs @@ -2,6 +2,7 @@ use { Error, Signature, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder, MemoryInstance, MemoryRef, TableInstance, TableRef, ModuleImportResolver, ModuleInstance, ModuleRef, RuntimeValue, TryInto, LoadedModule, load_from_buffer, TableDescriptor, MemoryDescriptor, + RuntimeArgs, }; use types::ValueType; use wabt::wat2wasm; @@ -78,25 +79,24 @@ impl Externals for TestHost { fn invoke_index( &mut self, index: usize, - args: &[RuntimeValue], + args: RuntimeArgs, ) -> Result, Error> { - let mut args = args.iter().cloned(); match index { SUB_FUNC_INDEX => { - let a: i32 = args.next().unwrap().try_into().unwrap(); - let b: i32 = args.next().unwrap().try_into().unwrap(); + let a: i32 = args.nth(0)?; + let b: i32 = args.nth(1)?; let result: RuntimeValue = (a - b).into(); Ok(Some(result)) } ERR_FUNC_INDEX => { - let error_code: u32 = args.next().unwrap().try_into().unwrap(); + let error_code = args.nth::(0)? as u32; let error = HostErrorWithCode { error_code }; Err(Error::Host(Box::new(error))) } INC_MEM_FUNC_INDEX => { - let ptr: u32 = args.next().unwrap().try_into().unwrap(); + let ptr = args.nth::(0)? as u32; let memory = self.memory.as_ref().expect( "Function 'inc_mem' expects attached memory", @@ -109,7 +109,7 @@ impl Externals for TestHost { Ok(None) } GET_MEM_FUNC_INDEX => { - let ptr: u32 = args.next().unwrap().try_into().unwrap(); + let ptr = args.nth::(0)? as u32; let memory = self.memory.as_ref().expect( "Function 'get_mem' expects attached memory", @@ -120,7 +120,7 @@ impl Externals for TestHost { Ok(Some(RuntimeValue::I32(buf[0] as i32))) } RECURSE_FUNC_INDEX => { - let val: RuntimeValue = args.next().unwrap(); + let val = args.nth_value(0)?; let instance = self.instance .as_ref() @@ -463,12 +463,11 @@ fn defer_providing_externals() { fn invoke_index( &mut self, index: usize, - args: &[RuntimeValue], + args: RuntimeArgs, ) -> Result, Error> { match index { INC_FUNC_INDEX => { - let mut args = args.iter().cloned(); - let a: u32 = args.next().unwrap().try_into().unwrap(); + let a = args.nth::(0)? as u32; *self.acc += a; Ok(None) } @@ -528,7 +527,7 @@ fn two_envs_one_externals() { fn invoke_index( &mut self, index: usize, - _args: &[RuntimeValue], + _args: RuntimeArgs, ) -> Result, Error> { match index { PRIVILEGED_FUNC_INDEX => { @@ -648,7 +647,7 @@ fn dynamically_add_host_func() { fn invoke_index( &mut self, index: usize, - _args: &[RuntimeValue], + _args: RuntimeArgs, ) -> Result, Error> { match index { ADD_FUNC_FUNC_INDEX => { From d340b990167daca353a489818a28305f340f2f6b Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 23 Jan 2018 14:42:20 +0300 Subject: [PATCH 3/4] fix build and address comments --- spec/src/run.rs | 6 +++--- src/host.rs | 6 ++++++ src/tests/host.rs | 3 +-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/spec/src/run.rs b/spec/src/run.rs index e85f833..a74b526 100644 --- a/spec/src/run.rs +++ b/spec/src/run.rs @@ -13,8 +13,8 @@ use wasmi::{ GlobalInstance, GlobalRef, ImportResolver, ImportsBuilder, MemoryInstance, MemoryRef, ModuleImportResolver, ModuleInstance, ModuleRef, RuntimeValue, TableInstance, TableRef, ValueType, - load_from_buffer, LoadedModule, Signature, MemoryDescriptor, - TableDescriptor, GlobalDescriptor, FuncInstance, + load_from_buffer, LoadedModule, Signature, MemoryDescriptor, + TableDescriptor, GlobalDescriptor, FuncInstance, RuntimeArgs, }; #[derive(Debug)] @@ -57,7 +57,7 @@ impl Externals for SpecModule { fn invoke_index( &mut self, index: usize, - args: &[RuntimeValue], + args: RuntimeArgs, ) -> Result, InterpreterError> { match index { PRINT_FUNC_INDEX => { diff --git a/src/host.rs b/src/host.rs index 4557f40..13e722f 100644 --- a/src/host.rs +++ b/src/host.rs @@ -3,6 +3,7 @@ use value::{RuntimeValue, TryInto}; use Error; /// Safe wrapper for list of arguments +#[derive(Debug)] pub struct RuntimeArgs<'a>(&'a [RuntimeValue]); impl<'a> From<&'a [RuntimeValue]> for RuntimeArgs<'a> { @@ -94,4 +95,9 @@ mod tests { assert_eq!(val, 0); } + #[test] + fn i64_invalid_arg_cast() { + let args: RuntimeArgs = (&[RuntimeValue::I64(90534534545322)][..]).into(); + assert!(args.nth::(0).is_err()); + } } \ No newline at end of file diff --git a/src/tests/host.rs b/src/tests/host.rs index 96570f3..7795753 100644 --- a/src/tests/host.rs +++ b/src/tests/host.rs @@ -1,8 +1,7 @@ use { Error, Signature, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder, MemoryInstance, MemoryRef, TableInstance, TableRef, ModuleImportResolver, ModuleInstance, ModuleRef, - RuntimeValue, TryInto, LoadedModule, load_from_buffer, TableDescriptor, MemoryDescriptor, - RuntimeArgs, + RuntimeValue, RuntimeArgs, LoadedModule, load_from_buffer, TableDescriptor, MemoryDescriptor, }; use types::ValueType; use wabt::wat2wasm; From 2133f782a429b9889abee781792923c0be8c2ad8 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 23 Jan 2018 14:43:09 +0300 Subject: [PATCH 4/4] fix doc comment --- src/host.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/host.rs b/src/host.rs index 13e722f..09b6c85 100644 --- a/src/host.rs +++ b/src/host.rs @@ -19,7 +19,7 @@ impl<'a> RuntimeArgs<'a> { Ok(self.nth_value(idx)?.try_into().map_err(|_| Error::Value("Invalid argument cast".to_owned()))?) } - /// Extract argument as a runtime value by index `idx` returning error is not enougn arguments + /// Extract argument as a runtime value by index `idx` returning error is not enough arguments pub fn nth_value(&self, idx: usize) -> Result { if self.0.len() <= idx { return Err(Error::Value("Invalid argument index".to_owned()));