diff --git a/CHANGELOG.md b/CHANGELOG.md index 461b96976..7eac1767c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ Blocks of changes will separated by version increments. ## **[Unreleased]** +- [#474](https://github.com/wasmerio/wasmer/pull/474) Set the install name of the dylib to `@rpath` +- [#490](https://github.com/wasmerio/wasmer/pull/490) Add MiddlewareChain and StreamingCompiler to runtime +- [#487](https://github.com/wasmerio/wasmer/pull/487) Fix stack offset check in singlepass backend +- [#450](https://github.com/wasmerio/wasmer/pull/450) Added Metering +- [#481](https://github.com/wasmerio/wasmer/pull/481) Added context trampoline into runtime - [#484](https://github.com/wasmerio/wasmer/pull/484) Fix bugs in emscripten socket syscalls - [#476](https://github.com/wasmerio/wasmer/pull/476) Fix bug with wasi::environ_get, fix off by one error in wasi::environ_sizes_get - [#470](https://github.com/wasmerio/wasmer/pull/470) Add mapdir support to Emscripten, implement getdents for Unix diff --git a/lib/emscripten/src/syscalls/mod.rs b/lib/emscripten/src/syscalls/mod.rs index a65cf48b5..052d773d9 100644 --- a/lib/emscripten/src/syscalls/mod.rs +++ b/lib/emscripten/src/syscalls/mod.rs @@ -41,7 +41,10 @@ use libc::{ write, // readlink, }; -use wasmer_runtime_core::vm::Ctx; +use wasmer_runtime_core::{ + memory::ptr::{Array, WasmPtr}, + vm::Ctx, +}; use super::env; use std::cell::Cell; @@ -77,7 +80,7 @@ pub fn ___syscall3(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { pub fn ___syscall4(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall4 (write) {}", _which); let fd: i32 = varargs.get(ctx); - let buf: u32 = varargs.get(ctx); + let buf: i32 = varargs.get(ctx); let count: i32 = varargs.get(ctx); debug!("=> fd: {}, buf: {}, count: {}", fd, buf, count); let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *const c_void; @@ -380,21 +383,18 @@ pub fn ___syscall163(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { // getcwd pub fn ___syscall183(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 { debug!("emscripten::___syscall183"); - let buf_offset: c_int = varargs.get(ctx); + let buf_offset: WasmPtr = varargs.get(ctx); let _size: c_int = varargs.get(ctx); let path = get_current_directory(ctx); let path_string = path.unwrap().display().to_string(); let len = path_string.len(); - unsafe { - let pointer_to_buffer = - emscripten_memory_pointer!(ctx.memory(0), buf_offset) as *mut libc::c_char; - let slice = slice::from_raw_parts_mut(pointer_to_buffer, len.clone()); - for (byte, loc) in path_string.bytes().zip(slice.iter_mut()) { - *loc = byte as _; - } - *pointer_to_buffer.add(len.clone()) = 0; + + let buf_writer = buf_offset.deref(ctx.memory(0), 0, len as u32 + 1).unwrap(); + for (i, byte) in path_string.bytes().enumerate() { + buf_writer[i].set(byte as i8); } - buf_offset + buf_writer[len].set(0); + buf_offset.offset() as i32 } // mmap2 diff --git a/lib/runtime-core/src/memory/mod.rs b/lib/runtime-core/src/memory/mod.rs index 6f532b6d4..04ffaa384 100644 --- a/lib/runtime-core/src/memory/mod.rs +++ b/lib/runtime-core/src/memory/mod.rs @@ -10,7 +10,7 @@ use crate::{ }; use std::{ cell::{Cell, RefCell}, - fmt, mem, ptr, + fmt, mem, rc::Rc, }; @@ -21,6 +21,7 @@ pub use self::view::{Atomically, MemoryView}; mod atomic; mod dynamic; +pub mod ptr; mod static_; mod view; @@ -221,9 +222,9 @@ struct UnsharedMemoryInternal { impl UnsharedMemory { pub fn new(desc: MemoryDescriptor) -> Result { let mut local = vm::LocalMemory { - base: ptr::null_mut(), + base: std::ptr::null_mut(), bound: 0, - memory: ptr::null_mut(), + memory: std::ptr::null_mut(), }; let storage = match desc.memory_type() { diff --git a/lib/runtime-core/src/memory/ptr.rs b/lib/runtime-core/src/memory/ptr.rs new file mode 100644 index 000000000..892668ce5 --- /dev/null +++ b/lib/runtime-core/src/memory/ptr.rs @@ -0,0 +1,125 @@ +//! A reusable pointer abstraction for getting memory from the guest's memory. +//! +//! This abstraction is safe: it ensures the memory is in bounds and that the pointer +//! is aligned (avoiding undefined behavior). +//! +//! Therefore, you should use this abstraction whenever possible to avoid memory +//! related bugs when implementing an ABI. + +use crate::{ + memory::Memory, + types::{ValueType, WasmExternType}, +}; +use std::{cell::Cell, fmt, marker::PhantomData, mem}; + +pub struct Array; +pub struct Item; + +#[repr(transparent)] +pub struct WasmPtr { + offset: u32, + _phantom: PhantomData<(T, Ty)>, +} + +impl WasmPtr { + #[inline] + pub fn new(offset: u32) -> Self { + Self { + offset, + _phantom: PhantomData, + } + } + + #[inline] + pub fn offset(self) -> u32 { + self.offset + } +} + +#[inline(always)] +fn align_pointer(ptr: usize, align: usize) -> usize { + // clears bits below aligment amount (assumes power of 2) to align pointer + debug_assert!(align.count_ones() == 1); + ptr & !(align - 1) +} + +impl WasmPtr { + #[inline] + pub fn deref<'a>(self, memory: &'a Memory) -> Option<&'a Cell> { + if (self.offset as usize) + mem::size_of::() >= memory.size().bytes().0 { + return None; + } + unsafe { + let cell_ptr = align_pointer( + memory.view::().as_ptr().add(self.offset as usize) as usize, + mem::align_of::(), + ) as *const Cell; + Some(&*cell_ptr) + } + } +} + +impl WasmPtr { + #[inline] + pub fn deref<'a>(self, memory: &'a Memory, index: u32, length: u32) -> Option<&'a [Cell]> { + // gets the size of the item in the array with padding added such that + // for any index, we will always result an aligned memory access + let item_size = mem::size_of::() + (mem::size_of::() % mem::align_of::()); + let slice_full_len = index as usize + length as usize; + + if (self.offset as usize) + (item_size * slice_full_len) >= memory.size().bytes().0 { + return None; + } + + unsafe { + let cell_ptr = align_pointer( + memory.view::().as_ptr().add(self.offset as usize) as usize, + mem::align_of::(), + ) as *const Cell; + let cell_ptrs = &std::slice::from_raw_parts(cell_ptr, slice_full_len) + [index as usize..slice_full_len]; + Some(cell_ptrs) + } + } +} + +unsafe impl WasmExternType for WasmPtr { + type Native = i32; + + fn to_native(self) -> Self::Native { + self.offset as i32 + } + fn from_native(n: Self::Native) -> Self { + Self { + offset: n as u32, + _phantom: PhantomData, + } + } +} + +unsafe impl ValueType for WasmPtr {} + +impl Clone for WasmPtr { + fn clone(&self) -> Self { + Self { + offset: self.offset, + _phantom: PhantomData, + } + } +} + +impl Copy for WasmPtr {} + +impl PartialEq for WasmPtr { + fn eq(&self, other: &Self) -> bool { + self.offset == other.offset + } +} + +impl Eq for WasmPtr {} + +impl fmt::Debug for WasmPtr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "WasmPtr({:#x})", self.offset) + } +} diff --git a/lib/wasi/src/ptr.rs b/lib/wasi/src/ptr.rs index 55a16d40c..0af012eac 100644 --- a/lib/wasi/src/ptr.rs +++ b/lib/wasi/src/ptr.rs @@ -1,114 +1,78 @@ +//! This is a wrapper around the `WasmPtr` abstraction that returns __WASI_EFAULT +//! if memory access failed + use crate::syscalls::types::{__wasi_errno_t, __WASI_EFAULT}; -use std::{cell::Cell, fmt, marker::PhantomData, mem}; +use std::{cell::Cell, fmt}; +pub use wasmer_runtime_core::memory::ptr::Array; use wasmer_runtime_core::{ - memory::Memory, + memory::{ptr, Memory}, types::{ValueType, WasmExternType}, }; -pub struct Array; -pub struct Item; - #[repr(transparent)] -pub struct WasmPtr { - offset: u32, - _phantom: PhantomData<(T, Ty)>, +pub struct WasmPtr(ptr::WasmPtr); + +unsafe impl ValueType for WasmPtr {} +impl Copy for WasmPtr {} + +impl Clone for WasmPtr { + fn clone(&self) -> Self { + Self(self.0.clone()) + } } +impl fmt::Debug for WasmPtr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self.0) + } +} + +unsafe impl WasmExternType for WasmPtr { + type Native = as WasmExternType>::Native; + + fn to_native(self) -> Self::Native { + self.0.to_native() + } + fn from_native(n: Self::Native) -> Self { + Self(ptr::WasmPtr::from_native(n)) + } +} + +impl PartialEq for WasmPtr { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl Eq for WasmPtr {} + impl WasmPtr { - #[inline] + #[inline(always)] pub fn new(offset: u32) -> Self { - Self { - offset, - _phantom: PhantomData, - } + Self(ptr::WasmPtr::new(offset)) } - #[inline] + #[inline(always)] pub fn offset(self) -> u32 { - self.offset + self.0.offset() } } -impl WasmPtr { - #[inline] +impl WasmPtr { + #[inline(always)] pub fn deref<'a>(self, memory: &'a Memory) -> Result<&'a Cell, __wasi_errno_t> { - if (self.offset as usize) + mem::size_of::() >= memory.size().bytes().0 { - return Err(__WASI_EFAULT); - } - unsafe { - // clears bits below aligment amount (assumes power of 2) to align pointer - let aligner = |ptr: usize, align: usize| ptr & !(align - 1); - let cell_ptr = aligner( - memory.view::().as_ptr().add(self.offset as usize) as usize, - mem::align_of::(), - ) as *const Cell; - Ok(&*cell_ptr) - } + self.0.deref(memory).ok_or(__WASI_EFAULT) } } -impl WasmPtr { - #[inline] +impl WasmPtr { + #[inline(always)] pub fn deref<'a>( self, memory: &'a Memory, index: u32, length: u32, ) -> Result<&'a [Cell], __wasi_errno_t> { - if (self.offset as usize) + (mem::size_of::() * ((index + length) as usize)) - >= memory.size().bytes().0 - { - return Err(__WASI_EFAULT); - } - - unsafe { - let cell_ptrs = memory.view::().get_unchecked( - ((self.offset as usize) / mem::size_of::()) + (index as usize) - ..((self.offset() as usize) / mem::size_of::()) - + ((index + length) as usize), - ) as *const _; - Ok(&*cell_ptrs) - } - } -} - -unsafe impl WasmExternType for WasmPtr { - type Native = i32; - - fn to_native(self) -> Self::Native { - self.offset as i32 - } - fn from_native(n: Self::Native) -> Self { - Self { - offset: n as u32, - _phantom: PhantomData, - } - } -} - -unsafe impl ValueType for WasmPtr {} - -impl Clone for WasmPtr { - fn clone(&self) -> Self { - Self { - offset: self.offset, - _phantom: PhantomData, - } - } -} - -impl Copy for WasmPtr {} - -impl PartialEq for WasmPtr { - fn eq(&self, other: &Self) -> bool { - self.offset == other.offset - } -} - -impl Eq for WasmPtr {} - -impl fmt::Debug for WasmPtr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "WasmPtr({:#x})", self.offset) + self.0.deref(memory, index, length).ok_or(__WASI_EFAULT) } }