diff --git a/common/sys/src/plugin/errors.rs b/common/sys/src/plugin/errors.rs index c7e686e24f..6e63172149 100644 --- a/common/sys/src/plugin/errors.rs +++ b/common/sys/src/plugin/errors.rs @@ -16,6 +16,13 @@ pub enum PluginModuleError { FunctionGet(ResolveError), Compile(wasmer_runtime::error::CompileError), Instantiate(wasmer_runtime::error::Error), + MemoryAllocation(MemoryAllocationError), RunFunction(RuntimeError), Encoding(Box), } + +#[derive(Debug)] +pub enum MemoryAllocationError { + AllocatorNotFound(ResolveError), + CantAllocate(RuntimeError), +} diff --git a/common/sys/src/plugin/module.rs b/common/sys/src/plugin/module.rs index f77c1f79d0..8920ff08b6 100644 --- a/common/sys/src/plugin/module.rs +++ b/common/sys/src/plugin/module.rs @@ -8,7 +8,7 @@ use std::{ use error::RuntimeError; use wasmer_runtime::*; -use super::errors::{PluginError, PluginModuleError}; +use super::errors::{MemoryAllocationError, PluginError, PluginModuleError}; use plugin_api::{Action, Event}; // This represent a WASM function interface @@ -60,8 +60,7 @@ impl PluginModule { Ok(e) => e, Err(e) => return Some(Err(e)), }; - let mem = instance.context().memory(0); - match execute_raw(&mem, &func, &request.bytes).map_err(PluginModuleError::RunFunction) { + match execute_raw(&instance, &func, &request.bytes).map_err(PluginModuleError::RunFunction) { Ok(e) => e, Err(e) => return Some(Err(e)), } @@ -92,22 +91,27 @@ impl PreparedEventQuery { } } -const MEMORY_POS: usize = 100000; - // This function is not public because this function should not be used without // an interface to limit unsafe behaviours #[allow(clippy::needless_range_loop)] fn execute_raw( - memory: &Memory, + instance: &Instance, function: &Function, bytes: &[u8], ) -> Result, RuntimeError> { - let view = memory.view::(); + // This reserves space for the buffer let len = bytes.len(); - for (cell, byte) in view[MEMORY_POS..len + MEMORY_POS].iter().zip(bytes.iter()) { - cell.set(*byte) - } - let start = function.call(MEMORY_POS as i32, len as u32)? as usize; + let start = { + let memory_pos = reserve_wasm_memory_buffer(len,instance).expect("Fatal error while allocating memory for a plugin! Closing server...") as usize; + let memory = instance.context().memory(0); + let view = memory.view::(); + for (cell, byte) in view[memory_pos..memory_pos+len].iter().zip(bytes.iter()) { + cell.set(*byte) + } + function.call(memory_pos as i32, len as u32)? as usize + }; + + let memory = instance.context().memory(0); let view = memory.view::(); let mut new_len_bytes = [0u8; 4]; // TODO: It is probably better to dirrectly make the new_len_bytes @@ -156,3 +160,15 @@ pub fn read_action(ctx: &mut Ctx, ptr: u32, len: u32) { } } } + +fn reserve_wasm_memory_buffer<'a>( + value: usize, + instance: &'a Instance, +) -> Result { + instance + .exports + .get::>("wasm_prepare_buffer") + .map_err(|e| MemoryAllocationError::AllocatorNotFound(e))? + .call(value as i32) + .map_err(|e| MemoryAllocationError::CantAllocate(e)) +} \ No newline at end of file diff --git a/plugin/rt/src/lib.rs b/plugin/rt/src/lib.rs index 81b3fadc65..a8dd8c9b2b 100644 --- a/plugin/rt/src/lib.rs +++ b/plugin/rt/src/lib.rs @@ -14,7 +14,7 @@ extern "C" { pub fn emit_action(action: api::Action) { emit_actions(vec![action]) } pub fn emit_actions(actions: Vec) { - let ret = bincode::serialize(&actions).unwrap(); + let ret = bincode::serialize(&actions).expect("Can't serialize action in emit"); unsafe { raw_emit_actions(ret.as_ptr(), ret.len()); } @@ -29,10 +29,21 @@ where } pub fn write_output(value: impl Serialize) -> i32 { - let ret = bincode::serialize(&value).unwrap(); + let ret = bincode::serialize(&value).expect("Can't serialize event output"); let len = ret.len() as u32; unsafe { ::std::ptr::write(1 as _, len); } ret.as_ptr() as _ } + +static mut BUFFERS: Vec = Vec::new(); + +/// Allocate buffer from wasm linear memory +#[no_mangle] +pub fn wasm_prepare_buffer(size: i32) -> i32 { + unsafe { + BUFFERS = Vec::::with_capacity(size as usize); + BUFFERS.as_ptr() as i32 + } +}