Merge pull request #2442 from wasmerio/features-cell

Improved WasmPtr, added WasmCell
This commit is contained in:
Syrus Akbary
2021-07-02 18:07:11 -05:00
committed by GitHub
11 changed files with 308 additions and 174 deletions

149
lib/api/src/cell.rs Normal file
View File

@@ -0,0 +1,149 @@
pub use std::cell::Cell;
use core::cmp::Ordering;
use core::fmt::{self, Debug};
use std::fmt::Pointer;
/// A mutable Wasm-memory location.
#[repr(transparent)]
pub struct WasmCell<'a, T: ?Sized> {
inner: &'a Cell<T>,
}
unsafe impl<T: ?Sized> Send for WasmCell<'_, T> where T: Send {}
unsafe impl<T: ?Sized> Sync for WasmCell<'_, T> {}
impl<'a, T: Copy> Clone for WasmCell<'a, T> {
#[inline]
fn clone(&self) -> WasmCell<'a, T> {
WasmCell { inner: self.inner }
}
}
impl<T: PartialEq + Copy> PartialEq for WasmCell<'_, T> {
#[inline]
fn eq(&self, other: &WasmCell<T>) -> bool {
self.inner.eq(&other.inner)
}
}
impl<T: Eq + Copy> Eq for WasmCell<'_, T> {}
impl<T: PartialOrd + Copy> PartialOrd for WasmCell<'_, T> {
#[inline]
fn partial_cmp(&self, other: &WasmCell<T>) -> Option<Ordering> {
self.inner.partial_cmp(&other.inner)
}
#[inline]
fn lt(&self, other: &WasmCell<T>) -> bool {
self.inner < other.inner
}
#[inline]
fn le(&self, other: &WasmCell<T>) -> bool {
self.inner <= other.inner
}
#[inline]
fn gt(&self, other: &WasmCell<T>) -> bool {
self.inner > other.inner
}
#[inline]
fn ge(&self, other: &WasmCell<T>) -> bool {
self.inner >= other.inner
}
}
impl<T: Ord + Copy> Ord for WasmCell<'_, T> {
#[inline]
fn cmp(&self, other: &WasmCell<T>) -> Ordering {
self.inner.cmp(&other.inner)
}
}
impl<'a, T> WasmCell<'a, T> {
/// Creates a new `WasmCell` containing the given value.
///
/// # Examples
///
/// ```
/// use std::cell::Cell;
/// use wasmer::WasmCell;
///
/// let cell = Cell::new(5);
/// let wasm_cell = WasmCell::new(&cell);
/// ```
#[inline]
pub const fn new(cell: &'a Cell<T>) -> WasmCell<'a, T> {
WasmCell { inner: cell }
}
}
impl<'a, T: Copy> WasmCell<'a, T> {
/// Returns a copy of the contained value.
///
/// # Examples
///
/// ```
/// use std::cell::Cell;
/// use wasmer::WasmCell;
///
/// let cell = Cell::new(5);
/// let wasm_cell = WasmCell::new(&cell);
/// let five = wasm_cell.get();
/// ```
#[inline]
pub fn get(&self) -> T {
self.inner.get()
}
/// Get an unsafe mutable pointer to the inner item
/// in the Cell.
///
/// # Safety
///
/// This method is highly discouraged to use. We have it for
/// compatibility reasons with Emscripten.
/// It is unsafe because changing an item inline will change
/// the underlying memory.
///
/// It's highly encouraged to use the `set` method instead.
#[deprecated(
since = "2.0.0",
note = "Please use the memory-safe set method instead"
)]
#[doc(hidden)]
pub unsafe fn get_mut(&self) -> &'a mut T {
&mut *self.inner.as_ptr()
}
}
impl<T: Debug> Debug for WasmCell<'_, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
impl<T: Sized> WasmCell<'_, T> {
/// Sets the contained value.
///
/// # Examples
///
/// ```
/// use std::cell::Cell;
/// use wasmer::WasmCell;
///
/// let cell = Cell::new(5);
/// let wasm_cell = WasmCell::new(&cell);
/// wasm_cell.set(10);
/// assert_eq!(cell.get(), 10);
/// ```
#[inline]
pub fn set(&self, val: T) {
self.inner.set(val);
}
}

View File

@@ -253,6 +253,7 @@
//! [wasmer-llvm]: https://docs.rs/wasmer-compiler-llvm/*/wasmer_compiler_llvm/
//! [wasmer-wasi]: https://docs.rs/wasmer-wasi/*/wasmer_wasi/
mod cell;
mod env;
mod exports;
mod externals;
@@ -281,6 +282,7 @@ pub mod internals {
pub use crate::externals::{WithEnv, WithoutEnv};
}
pub use crate::cell::WasmCell;
pub use crate::env::{HostEnvInitError, LazyInit, WasmerEnv};
pub use crate::exports::{ExportError, Exportable, Exports, ExportsIterator};
pub use crate::externals::{

View File

@@ -6,6 +6,7 @@
//! Therefore, you should use this abstraction whenever possible to avoid memory
//! related bugs when implementing an ABI.
use crate::cell::WasmCell;
use crate::{externals::Memory, FromToNativeWasmType};
use std::{cell::Cell, fmt, marker::PhantomData, mem};
use wasmer_types::ValueType;
@@ -103,7 +104,7 @@ impl<T: Copy + ValueType> WasmPtr<T, Item> {
/// If you're unsure what that means, it likely does not apply to you.
/// This invariant will be enforced in the future.
#[inline]
pub fn deref<'a>(self, memory: &'a Memory) -> Option<&'a Cell<T>> {
pub fn deref<'a>(self, memory: &'a Memory) -> Option<WasmCell<'a, T>> {
if (self.offset as usize) + mem::size_of::<T>() > memory.size().bytes().0
|| mem::size_of::<T>() == 0
{
@@ -114,30 +115,9 @@ impl<T: Copy + ValueType> WasmPtr<T, Item> {
memory.view::<u8>().as_ptr().add(self.offset as usize) as usize,
mem::align_of::<T>(),
) as *const Cell<T>;
Some(&*cell_ptr)
Some(WasmCell::new(&*cell_ptr))
}
}
/// Mutably dereference this `WasmPtr` getting a `&mut Cell<T>` allowing for
/// direct access to a `&mut T`.
///
/// # Safety
/// - This method does not do any aliasing checks: it's possible to create
/// `&mut T` that point to the same memory. You should ensure that you have
/// exclusive access to Wasm linear memory before calling this method.
#[inline]
pub unsafe fn deref_mut<'a>(self, memory: &'a Memory) -> Option<&'a mut Cell<T>> {
if (self.offset as usize) + mem::size_of::<T>() > memory.size().bytes().0
|| mem::size_of::<T>() == 0
{
return None;
}
let cell_ptr = align_pointer(
memory.view::<u8>().as_ptr().add(self.offset as usize) as usize,
mem::align_of::<T>(),
) as *mut Cell<T>;
Some(&mut *cell_ptr)
}
}
/// Methods for `WasmPtr`s to arrays of data that can be dereferenced, namely to
@@ -151,7 +131,12 @@ impl<T: Copy + ValueType> WasmPtr<T, Array> {
/// If you're unsure what that means, it likely does not apply to you.
/// This invariant will be enforced in the future.
#[inline]
pub fn deref(self, memory: &Memory, index: u32, length: u32) -> Option<&[Cell<T>]> {
pub fn deref<'a>(
self,
memory: &'a Memory,
index: u32,
length: u32,
) -> Option<Vec<WasmCell<'a, T>>> {
// 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::<T>();
@@ -159,57 +144,24 @@ impl<T: Copy + ValueType> WasmPtr<T, Array> {
let memory_size = memory.size().bytes().0;
if (self.offset as usize) + (item_size * slice_full_len) > memory_size
|| self.offset as usize >= memory_size
|| mem::size_of::<T>() == 0
|| (self.offset as usize) >= memory_size
|| item_size == 0
{
return None;
}
unsafe {
let cell_ptrs = unsafe {
let cell_ptr = align_pointer(
memory.view::<u8>().as_ptr().add(self.offset as usize) as usize,
mem::align_of::<T>(),
) as *const Cell<T>;
let cell_ptrs = &std::slice::from_raw_parts(cell_ptr, slice_full_len)
[index as usize..slice_full_len];
Some(cell_ptrs)
}
}
&std::slice::from_raw_parts(cell_ptr, slice_full_len)[index as usize..slice_full_len]
};
/// Mutably dereference this `WasmPtr` getting a `&mut [Cell<T>]` allowing for
/// direct access to a `&mut [T]`.
///
/// # Safety
/// - This method does not do any aliasing checks: it's possible to create
/// `&mut T` that point to the same memory. You should ensure that you have
/// exclusive access to Wasm linear memory before calling this method.
#[inline]
pub unsafe fn deref_mut(
self,
memory: &Memory,
index: u32,
length: u32,
) -> Option<&mut [Cell<T>]> {
// 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::<T>();
let slice_full_len = index as usize + length as usize;
let memory_size = memory.size().bytes().0;
if (self.offset as usize) + (item_size * slice_full_len) > memory.size().bytes().0
|| self.offset as usize >= memory_size
|| mem::size_of::<T>() == 0
{
return None;
}
let cell_ptr = align_pointer(
memory.view::<u8>().as_ptr().add(self.offset as usize) as usize,
mem::align_of::<T>(),
) as *mut Cell<T>;
let cell_ptrs = &mut std::slice::from_raw_parts_mut(cell_ptr, slice_full_len)
[index as usize..slice_full_len];
Some(cell_ptrs)
let wasm_cells = cell_ptrs
.iter()
.map(|ptr| WasmCell::new(ptr))
.collect::<Vec<_>>();
Some(wasm_cells)
}
/// Get a UTF-8 string from the `WasmPtr` with the given length.
@@ -339,7 +291,7 @@ mod test {
use crate::{Memory, MemoryType, Store};
/// Ensure that memory accesses work on the edges of memory and that out of
/// bounds errors are caught with both `deref` and `deref_mut`.
/// bounds errors are caught with `deref`
#[test]
fn wasm_ptr_memory_bounds_checks_hold() {
// create a memory
@@ -352,29 +304,23 @@ mod test {
let start_wasm_ptr_array: WasmPtr<u8, Array> = WasmPtr::new(0);
assert!(start_wasm_ptr.deref(&memory).is_some());
assert!(unsafe { start_wasm_ptr.deref_mut(&memory).is_some() });
assert!(start_wasm_ptr_array.deref(&memory, 0, 0).is_some());
assert!(unsafe { start_wasm_ptr_array.get_utf8_str(&memory, 0).is_some() });
assert!(start_wasm_ptr_array.get_utf8_string(&memory, 0).is_some());
assert!(unsafe { start_wasm_ptr_array.deref_mut(&memory, 0, 0).is_some() });
assert!(start_wasm_ptr_array.deref(&memory, 0, 1).is_some());
assert!(unsafe { start_wasm_ptr_array.deref_mut(&memory, 0, 1).is_some() });
// test that accessing the last valid memory address works correctly and OOB is caught
let last_valid_address_for_u8 = (memory.size().bytes().0 - 1) as u32;
let end_wasm_ptr: WasmPtr<u8> = WasmPtr::new(last_valid_address_for_u8);
assert!(end_wasm_ptr.deref(&memory).is_some());
assert!(unsafe { end_wasm_ptr.deref_mut(&memory).is_some() });
let end_wasm_ptr_array: WasmPtr<u8, Array> = WasmPtr::new(last_valid_address_for_u8);
assert!(end_wasm_ptr_array.deref(&memory, 0, 1).is_some());
assert!(unsafe { end_wasm_ptr_array.deref_mut(&memory, 0, 1).is_some() });
let invalid_idx_len_combos: [(u32, u32); 3] =
[(last_valid_address_for_u8 + 1, 0), (0, 2), (1, 1)];
for &(idx, len) in invalid_idx_len_combos.iter() {
assert!(end_wasm_ptr_array.deref(&memory, idx, len).is_none());
assert!(unsafe { end_wasm_ptr_array.deref_mut(&memory, idx, len).is_none() });
}
assert!(unsafe { end_wasm_ptr_array.get_utf8_str(&memory, 2).is_none() });
assert!(end_wasm_ptr_array.get_utf8_string(&memory, 2).is_none());
@@ -384,9 +330,7 @@ mod test {
let last_valid_address_for_u32 = (memory.size().bytes().0 - 4) as u32;
let end_wasm_ptr: WasmPtr<u32> = WasmPtr::new(last_valid_address_for_u32);
assert!(end_wasm_ptr.deref(&memory).is_some());
assert!(unsafe { end_wasm_ptr.deref_mut(&memory).is_some() });
assert!(end_wasm_ptr.deref(&memory).is_some());
assert!(unsafe { end_wasm_ptr.deref_mut(&memory).is_some() });
let end_wasm_ptr_oob_array: [WasmPtr<u32>; 4] = [
WasmPtr::new(last_valid_address_for_u32 + 1),
@@ -396,17 +340,14 @@ mod test {
];
for oob_end_ptr in end_wasm_ptr_oob_array.iter() {
assert!(oob_end_ptr.deref(&memory).is_none());
assert!(unsafe { oob_end_ptr.deref_mut(&memory).is_none() });
}
let end_wasm_ptr_array: WasmPtr<u32, Array> = WasmPtr::new(last_valid_address_for_u32);
assert!(end_wasm_ptr_array.deref(&memory, 0, 1).is_some());
assert!(unsafe { end_wasm_ptr_array.deref_mut(&memory, 0, 1).is_some() });
let invalid_idx_len_combos: [(u32, u32); 3] =
[(last_valid_address_for_u32 + 1, 0), (0, 2), (1, 1)];
for &(idx, len) in invalid_idx_len_combos.iter() {
assert!(end_wasm_ptr_array.deref(&memory, idx, len).is_none());
assert!(unsafe { end_wasm_ptr_array.deref_mut(&memory, idx, len).is_none() });
}
let end_wasm_ptr_array_oob_array: [WasmPtr<u32, Array>; 4] = [
@@ -418,9 +359,7 @@ mod test {
for oob_end_array_ptr in end_wasm_ptr_array_oob_array.iter() {
assert!(oob_end_array_ptr.deref(&memory, 0, 1).is_none());
assert!(unsafe { oob_end_array_ptr.deref_mut(&memory, 0, 1).is_none() });
assert!(oob_end_array_ptr.deref(&memory, 1, 0).is_none());
assert!(unsafe { oob_end_array_ptr.deref_mut(&memory, 1, 0).is_none() });
}
}
}

View File

@@ -3,7 +3,6 @@ use libc::{
c_int, getenv, getgrnam as libc_getgrnam, getpwnam as libc_getpwnam, putenv, setenv, sysconf,
unsetenv,
};
use std::cell::Cell;
use std::ffi::CStr;
use std::mem;
use std::os::raw::c_char;
@@ -152,11 +151,7 @@ pub fn _gai_strerror(ctx: &EmEnv, ecode: i32) -> i32 {
let string_on_guest: WasmPtr<c_char, Array> = call_malloc_with_cast(ctx, bytes.len() as _);
let memory = ctx.memory(0);
let writer = unsafe {
string_on_guest
.deref_mut(&memory, 0, bytes.len() as _)
.unwrap()
};
let writer = string_on_guest.deref(&memory, 0, bytes.len() as _).unwrap();
for (i, byte) in bytes.iter().enumerate() {
writer[i].set(*byte as _);
}
@@ -174,21 +169,23 @@ pub fn _getaddrinfo(
use libc::{addrinfo, freeaddrinfo};
debug!("emscripten::_getaddrinfo");
let memory = ctx.memory(0);
debug!(" => node = {}", unsafe {
debug!(" => node = {}", {
node_ptr
.deref(&memory)
.map(|np| {
std::ffi::CStr::from_ptr(np as *const Cell<c_char> as *const c_char)
.to_string_lossy()
.map(|_np| {
unimplemented!();
// std::ffi::CStr::from_ptr(np as *const Cell<c_char> as *const c_char)
// .to_string_lossy()
})
.unwrap_or(std::borrow::Cow::Borrowed("null"))
});
debug!(" => server_str = {}", unsafe {
debug!(" => server_str = {}", {
service_str_ptr
.deref(&memory)
.map(|np| {
std::ffi::CStr::from_ptr(np as *const Cell<c_char> as *const c_char)
.to_string_lossy()
.map(|_np| {
unimplemented!();
// std::ffi::CStr::from_ptr(np as *const Cell<c_char> as *const c_char)
// .to_string_lossy()
})
.unwrap_or(std::borrow::Cow::Borrowed("null"))
});
@@ -212,13 +209,17 @@ pub fn _getaddrinfo(
// allocate equivalent memory for res_val_ptr
let result = unsafe {
libc::getaddrinfo(
(node_ptr
.deref(&memory)
.map(|m| m as *const Cell<c_char> as *const c_char))
(node_ptr.deref(&memory).map(|_m| {
unimplemented!();
//m as *const Cell<c_char> as *const c_char
}))
.unwrap_or(std::ptr::null()),
service_str_ptr
.deref(&memory)
.map(|m| m as *const Cell<c_char> as *const c_char)
.map(|_m| {
unimplemented!();
// m as *const Cell<c_char> as *const c_char
})
.unwrap_or(std::ptr::null()),
hints
.as_ref()
@@ -246,7 +247,7 @@ pub fn _getaddrinfo(
// connect list
if let Some(prev_guest) = previous_guest_node {
let mut pg = prev_guest.deref_mut(&memory).unwrap().get_mut();
let mut pg = prev_guest.deref(&memory).unwrap().get_mut();
pg.ai_next = current_guest_node_ptr;
}
@@ -258,7 +259,7 @@ pub fn _getaddrinfo(
let host_sockaddr_ptr = (*current_host_node).ai_addr;
let guest_sockaddr_ptr: WasmPtr<EmSockAddr> =
call_malloc_with_cast(ctx, host_addrlen as _);
let guest_sockaddr = guest_sockaddr_ptr.deref_mut(&memory).unwrap().get_mut();
let guest_sockaddr = guest_sockaddr_ptr.deref(&memory).unwrap().get_mut();
guest_sockaddr.sa_family = (*host_sockaddr_ptr).sa_family as i16;
guest_sockaddr.sa_data = (*host_sockaddr_ptr).sa_data;
@@ -287,8 +288,7 @@ pub fn _getaddrinfo(
}
};
let mut current_guest_node =
current_guest_node_ptr.deref_mut(&memory).unwrap().get_mut();
let mut current_guest_node = current_guest_node_ptr.deref(&memory).unwrap().get_mut();
current_guest_node.ai_flags = (*current_host_node).ai_flags;
current_guest_node.ai_family = (*current_host_node).ai_family;
current_guest_node.ai_socktype = (*current_host_node).ai_socktype;

View File

@@ -5,8 +5,8 @@
// don't want to warn about unusued code here
#![allow(dead_code)]
use std::{cell::Cell, fmt};
pub use wasmer::{Array, FromToNativeWasmType, Memory, ValueType};
use std::fmt;
pub use wasmer::{Array, FromToNativeWasmType, Memory, ValueType, WasmCell};
#[repr(transparent)]
pub struct WasmPtr<T: Copy, Ty = wasmer::Item>(wasmer::WasmPtr<T, Ty>);
@@ -59,45 +59,27 @@ impl<T: Copy, Ty> WasmPtr<T, Ty> {
impl<T: Copy + ValueType> WasmPtr<T, wasmer::Item> {
#[inline(always)]
pub fn deref<'a>(self, memory: &'a Memory) -> Option<&'a Cell<T>> {
pub fn deref<'a>(self, memory: &'a Memory) -> Option<WasmCell<'a, T>> {
if self.0.offset() == 0 {
None
} else {
self.0.deref(memory)
}
}
#[inline(always)]
pub unsafe fn deref_mut<'a>(self, memory: &'a Memory) -> Option<&'a mut Cell<T>> {
if self.0.offset() == 0 {
None
} else {
self.0.deref_mut(memory)
}
}
}
impl<T: Copy + ValueType> WasmPtr<T, wasmer::Array> {
#[inline(always)]
pub fn deref<'a>(self, memory: &'a Memory, index: u32, length: u32) -> Option<&'a [Cell<T>]> {
if self.0.offset() == 0 {
None
} else {
self.0.deref(memory, index, length)
}
}
#[inline]
pub unsafe fn deref_mut<'a>(
pub fn deref<'a>(
self,
memory: &'a Memory,
index: u32,
length: u32,
) -> Option<&'a mut [Cell<T>]> {
) -> Option<Vec<WasmCell<'a, T>>> {
if self.0.offset() == 0 {
None
} else {
self.0.deref_mut(memory, index, length)
self.0.deref(memory, index, length)
}
}

View File

@@ -633,7 +633,7 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
address.deref(&memory).unwrap().get(),
address_len.deref(&memory).unwrap().get()
);
let address_len_addr = unsafe { address_len.deref_mut(&memory).unwrap().get_mut() };
let address_len_addr = unsafe { address_len.deref(&memory).unwrap().get_mut() };
// let mut address_len_addr: socklen_t = 0;
let mut host_address: sockaddr = sockaddr {
@@ -643,7 +643,7 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
sa_len: Default::default(),
};
let fd = unsafe { accept(socket, &mut host_address, address_len_addr) };
let address_addr = unsafe { address.deref_mut(&memory).unwrap().get_mut() };
let address_addr = unsafe { address.deref(&memory).unwrap().get_mut() };
address_addr.sa_family = host_address.sa_family as _;
address_addr.sa_data = host_address.sa_data;
@@ -667,7 +667,7 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
let socket: i32 = socket_varargs.get(ctx);
let address: WasmPtr<EmSockAddr> = socket_varargs.get(ctx);
let address_len: WasmPtr<u32> = socket_varargs.get(ctx);
let address_len_addr = unsafe { address_len.deref_mut(&memory).unwrap().get_mut() };
let address_len_addr = unsafe { address_len.deref(&memory).unwrap().get_mut() };
let mut sock_addr_host: sockaddr = sockaddr {
sa_family: Default::default(),
@@ -683,7 +683,7 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
)
};
// translate from host data into emscripten data
let mut address_mut = unsafe { address.deref_mut(&memory).unwrap().get_mut() };
let mut address_mut = unsafe { address.deref(&memory).unwrap().get_mut() };
address_mut.sa_family = sock_addr_host.sa_family as _;
address_mut.sa_data = sock_addr_host.sa_data;
@@ -857,7 +857,7 @@ pub fn ___syscall168(ctx: &EmEnv, _which: i32, mut varargs: VarArgs) -> i32 {
let timeout: i32 = varargs.get(ctx);
let memory = ctx.memory(0);
let fds_mut = unsafe { fds.deref_mut(&memory).unwrap().get_mut() };
let fds_mut = unsafe { fds.deref(&memory).unwrap().get_mut() };
let ret = unsafe {
libc::poll(

View File

@@ -1,6 +1,7 @@
use crate::lib::std::cell::Cell;
use crate::lib::std::marker::PhantomData;
use crate::lib::std::ops::Deref;
use crate::lib::std::ops::{Bound, RangeBounds};
use crate::lib::std::slice;
use crate::lib::std::sync::atomic::{
AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicU16, AtomicU32, AtomicU64, AtomicU8,
@@ -48,6 +49,8 @@ impl Atomicity for NonAtomically {}
/// A view into a memory.
pub struct MemoryView<'a, T: 'a, A = NonAtomically> {
ptr: *mut T,
// Note: the length is in the terms of `size::<T>()`.
// The total length in memory is `size::<T>() * length`.
length: usize,
_phantom: PhantomData<(&'a [Cell<T>], A)>,
}
@@ -64,6 +67,50 @@ where
_phantom: PhantomData,
}
}
/// Creates a subarray view from this MemoryView.
pub fn subarray(&self, range: impl RangeBounds<usize>) -> Self {
let start: usize = match range.start_bound() {
Bound::Unbounded => 0,
Bound::Included(start) => *start,
Bound::Excluded(start) => *start + 1,
};
let end: usize = match range.end_bound() {
Bound::Unbounded => self.length,
Bound::Included(end) => *end,
Bound::Excluded(end) => *end - 1,
};
assert!(
start < self.length,
"The range start is bigger than current length"
);
assert!(
end < self.length,
"The range end is bigger than current length"
);
Self {
ptr: unsafe { self.ptr.add(start) },
length: (end - start),
_phantom: PhantomData,
}
}
/// Copy the contents of the source slice into this `MemoryView`.
///
/// This function will efficiently copy the memory from within the wasm
/// modules own linear memory to this typed array.
///
/// # Safety
///
/// This method is unsafe because the caller will need to make sure
/// there are no data races when copying memory into the view.
pub unsafe fn copy_from(&self, src: &[T]) {
// We cap at a max length
let sliced_src = &src[..self.length];
for (i, byte) in sliced_src.iter().enumerate() {
*self.ptr.offset(i as isize) = *byte;
}
}
}
impl<'a, T: Atomic> MemoryView<'a, T> {

View File

@@ -2,8 +2,10 @@
//! if memory access failed
use crate::syscalls::types::{__wasi_errno_t, __WASI_EFAULT};
use std::{cell::Cell, fmt};
pub use wasmer::{Array, FromToNativeWasmType, Item, Memory, ValueType, WasmPtr as BaseWasmPtr};
use std::fmt;
pub use wasmer::{
Array, FromToNativeWasmType, Item, Memory, ValueType, WasmCell, WasmPtr as BaseWasmPtr,
};
#[repr(transparent)]
pub struct WasmPtr<T: Copy, Ty = Item>(BaseWasmPtr<T, Ty>);
@@ -63,7 +65,7 @@ impl<T: Copy, Ty> WasmPtr<T, Ty> {
impl<T: Copy + ValueType> WasmPtr<T, Item> {
#[inline(always)]
pub fn deref<'a>(self, memory: &'a Memory) -> Result<&'a Cell<T>, __wasi_errno_t> {
pub fn deref<'a>(self, memory: &'a Memory) -> Result<WasmCell<'a, T>, __wasi_errno_t> {
self.0.deref(memory).ok_or(__WASI_EFAULT)
}
}
@@ -75,7 +77,7 @@ impl<T: Copy + ValueType> WasmPtr<T, Array> {
memory: &'a Memory,
index: u32,
length: u32,
) -> Result<&'a [Cell<T>], __wasi_errno_t> {
) -> Result<Vec<WasmCell<'a, T>>, __wasi_errno_t> {
self.0.deref(memory, index, length).ok_or(__WASI_EFAULT)
}

View File

@@ -27,11 +27,10 @@ use crate::{
WasiEnv, WasiError,
};
use std::borrow::Borrow;
use std::cell::Cell;
use std::convert::{Infallible, TryInto};
use std::io::{self, Read, Seek, Write};
use tracing::{debug, trace};
use wasmer::{Memory, RuntimeError, Value};
use wasmer::{Memory, RuntimeError, Value, WasmCell};
#[cfg(any(
target_os = "freebsd",
@@ -47,7 +46,7 @@ pub use windows::*;
fn write_bytes_inner<T: Write>(
mut write_loc: T,
memory: &Memory,
iovs_arr_cell: &[Cell<__wasi_ciovec_t>],
iovs_arr_cell: &[WasmCell<__wasi_ciovec_t>],
) -> Result<u32, __wasi_errno_t> {
let mut bytes_written = 0;
for iov in iovs_arr_cell {
@@ -66,7 +65,7 @@ fn write_bytes_inner<T: Write>(
fn write_bytes<T: Write>(
mut write_loc: T,
memory: &Memory,
iovs_arr_cell: &[Cell<__wasi_ciovec_t>],
iovs_arr_cell: &[WasmCell<__wasi_ciovec_t>],
) -> Result<u32, __wasi_errno_t> {
let result = write_bytes_inner(&mut write_loc, memory, iovs_arr_cell);
write_loc.flush();
@@ -76,16 +75,27 @@ fn write_bytes<T: Write>(
fn read_bytes<T: Read>(
mut reader: T,
memory: &Memory,
iovs_arr_cell: &[Cell<__wasi_iovec_t>],
iovs_arr_cell: &[WasmCell<__wasi_iovec_t>],
) -> Result<u32, __wasi_errno_t> {
let mut bytes_read = 0;
// We allocate the raw_bytes first once instead of
// N times in the loop.
let mut raw_bytes: Vec<u8> = vec![0; 1024];
for iov in iovs_arr_cell {
let iov_inner = iov.get();
let bytes = WasmPtr::<u8, Array>::new(iov_inner.buf).deref(memory, 0, iov_inner.buf_len)?;
let mut raw_bytes: &mut [u8] =
unsafe { &mut *(bytes as *const [_] as *mut [_] as *mut [u8]) };
bytes_read += reader.read(raw_bytes).map_err(|_| __WASI_EIO)? as u32;
raw_bytes.clear();
raw_bytes.resize(iov_inner.buf_len as usize, 0);
bytes_read += reader.read(&mut raw_bytes).map_err(|_| __WASI_EIO)? as u32;
unsafe {
memory
.view::<u8>()
.subarray(
iov_inner.buf as usize..=(iov_inner.buf as usize + iov_inner.buf_len as usize),
)
.copy_from(&raw_bytes);
}
}
Ok(bytes_read)
}
@@ -660,7 +670,7 @@ pub fn fd_pread(
if let Some(ref mut stdin) =
wasi_try!(state.fs.stdin_mut().map_err(WasiFsError::into_wasi_err))
{
wasi_try!(read_bytes(stdin, memory, iov_cells))
wasi_try!(read_bytes(stdin, memory, &iov_cells))
} else {
return __WASI_EBADF;
}
@@ -687,7 +697,7 @@ pub fn fd_pread(
h.seek(std::io::SeekFrom::Start(offset as u64)).ok(),
__WASI_EIO
);
wasi_try!(read_bytes(h, memory, iov_cells))
wasi_try!(read_bytes(h, memory, &iov_cells))
} else {
return __WASI_EINVAL;
}
@@ -695,7 +705,7 @@ pub fn fd_pread(
Kind::Dir { .. } | Kind::Root { .. } => return __WASI_EISDIR,
Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_pread"),
Kind::Buffer { buffer } => {
wasi_try!(read_bytes(&buffer[(offset as usize)..], memory, iov_cells))
wasi_try!(read_bytes(&buffer[(offset as usize)..], memory, &iov_cells))
}
}
}
@@ -809,7 +819,7 @@ pub fn fd_pwrite(
if let Some(ref mut stdout) =
wasi_try!(state.fs.stdout_mut().map_err(WasiFsError::into_wasi_err))
{
wasi_try!(write_bytes(stdout, memory, iovs_arr_cell))
wasi_try!(write_bytes(stdout, memory, &iovs_arr_cell))
} else {
return __WASI_EBADF;
}
@@ -818,7 +828,7 @@ pub fn fd_pwrite(
if let Some(ref mut stderr) =
wasi_try!(state.fs.stderr_mut().map_err(WasiFsError::into_wasi_err))
{
wasi_try!(write_bytes(stderr, memory, iovs_arr_cell))
wasi_try!(write_bytes(stderr, memory, &iovs_arr_cell))
} else {
return __WASI_EBADF;
}
@@ -839,7 +849,7 @@ pub fn fd_pwrite(
Kind::File { handle, .. } => {
if let Some(handle) = handle {
handle.seek(std::io::SeekFrom::Start(offset as u64));
wasi_try!(write_bytes(handle, memory, iovs_arr_cell))
wasi_try!(write_bytes(handle, memory, &iovs_arr_cell))
} else {
return __WASI_EINVAL;
}
@@ -853,7 +863,7 @@ pub fn fd_pwrite(
wasi_try!(write_bytes(
&mut buffer[(offset as usize)..],
memory,
iovs_arr_cell
&iovs_arr_cell
))
}
}
@@ -895,7 +905,7 @@ pub fn fd_read(
if let Some(ref mut stdin) =
wasi_try!(state.fs.stdin_mut().map_err(WasiFsError::into_wasi_err))
{
wasi_try!(read_bytes(stdin, memory, iovs_arr_cell))
wasi_try!(read_bytes(stdin, memory, &iovs_arr_cell))
} else {
return __WASI_EBADF;
}
@@ -917,7 +927,7 @@ pub fn fd_read(
Kind::File { handle, .. } => {
if let Some(handle) = handle {
handle.seek(std::io::SeekFrom::Start(offset as u64));
wasi_try!(read_bytes(handle, memory, iovs_arr_cell))
wasi_try!(read_bytes(handle, memory, &iovs_arr_cell))
} else {
return __WASI_EINVAL;
}
@@ -928,7 +938,7 @@ pub fn fd_read(
}
Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_read"),
Kind::Buffer { buffer } => {
wasi_try!(read_bytes(&buffer[offset..], memory, iovs_arr_cell))
wasi_try!(read_bytes(&buffer[offset..], memory, &iovs_arr_cell))
}
};
@@ -1266,7 +1276,7 @@ pub fn fd_write(
if let Some(ref mut stdout) =
wasi_try!(state.fs.stdout_mut().map_err(WasiFsError::into_wasi_err))
{
wasi_try!(write_bytes(stdout, memory, iovs_arr_cell))
wasi_try!(write_bytes(stdout, memory, &iovs_arr_cell))
} else {
return __WASI_EBADF;
}
@@ -1275,7 +1285,7 @@ pub fn fd_write(
if let Some(ref mut stderr) =
wasi_try!(state.fs.stderr_mut().map_err(WasiFsError::into_wasi_err))
{
wasi_try!(write_bytes(stderr, memory, iovs_arr_cell))
wasi_try!(write_bytes(stderr, memory, &iovs_arr_cell))
} else {
return __WASI_EBADF;
}
@@ -1295,7 +1305,7 @@ pub fn fd_write(
Kind::File { handle, .. } => {
if let Some(handle) = handle {
handle.seek(std::io::SeekFrom::Start(offset as u64));
wasi_try!(write_bytes(handle, memory, iovs_arr_cell))
wasi_try!(write_bytes(handle, memory, &iovs_arr_cell))
} else {
return __WASI_EINVAL;
}
@@ -1306,7 +1316,7 @@ pub fn fd_write(
}
Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_write"),
Kind::Buffer { buffer } => {
wasi_try!(write_bytes(&mut buffer[offset..], memory, iovs_arr_cell))
wasi_try!(write_bytes(&mut buffer[offset..], memory, &iovs_arr_cell))
}
};
@@ -2515,18 +2525,21 @@ pub fn proc_raise(env: &WasiEnv, sig: __wasi_signal_t) -> __wasi_errno_t {
/// A pointer to a buffer where the random bytes will be written
/// - `size_t buf_len`
/// The number of bytes that will be written
pub fn random_get(env: &WasiEnv, buf: WasmPtr<u8, Array>, buf_len: u32) -> __wasi_errno_t {
pub fn random_get(env: &WasiEnv, buf: u32, buf_len: u32) -> __wasi_errno_t {
debug!("wasi::random_get buf_len: {}", buf_len);
let memory = env.memory();
let buf = wasi_try!(buf.deref(memory, 0, buf_len));
let res = unsafe {
let u8_buffer = &mut *(buf as *const [_] as *mut [_] as *mut [u8]);
getrandom::getrandom(u8_buffer)
};
let mut u8_buffer = vec![0; buf_len as usize];
let res = getrandom::getrandom(&mut u8_buffer);
match res {
Ok(()) => __WASI_ESUCCESS,
Ok(()) => {
unsafe {
memory
.view::<u8>()
.subarray(buf as usize..=(buf as usize + buf_len as usize))
.copy_from(&u8_buffer);
}
__WASI_ESUCCESS
}
Err(_) => __WASI_EIO,
}
}

View File

@@ -3,12 +3,12 @@ use libc::{
clock_getres, clock_gettime, timespec, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID,
CLOCK_REALTIME, CLOCK_THREAD_CPUTIME_ID,
};
use std::cell::Cell;
use std::mem;
use wasmer::WasmCell;
pub fn platform_clock_res_get(
clock_id: __wasi_clockid_t,
resolution: &Cell<__wasi_timestamp_t>,
resolution: WasmCell<__wasi_timestamp_t>,
) -> __wasi_errno_t {
let unix_clock_id = match clock_id {
__WASI_CLOCK_MONOTONIC => CLOCK_MONOTONIC,
@@ -36,7 +36,7 @@ pub fn platform_clock_res_get(
pub fn platform_clock_time_get(
clock_id: __wasi_clockid_t,
precision: __wasi_timestamp_t,
time: &Cell<__wasi_timestamp_t>,
time: WasmCell<__wasi_timestamp_t>,
) -> __wasi_errno_t {
let unix_clock_id = match clock_id {
__WASI_CLOCK_MONOTONIC => CLOCK_MONOTONIC,

View File

@@ -1,10 +1,10 @@
use crate::syscalls::types::*;
use std::cell::Cell;
use tracing::debug;
use wasmer::WasmCell;
pub fn platform_clock_res_get(
clock_id: __wasi_clockid_t,
resolution: &Cell<__wasi_timestamp_t>,
resolution: WasmCell<__wasi_timestamp_t>,
) -> __wasi_errno_t {
let resolution_val = match clock_id {
// resolution of monotonic clock at 10ms, from:
@@ -27,7 +27,7 @@ pub fn platform_clock_res_get(
pub fn platform_clock_time_get(
clock_id: __wasi_clockid_t,
precision: __wasi_timestamp_t,
time: &Cell<__wasi_timestamp_t>,
time: WasmCell<__wasi_timestamp_t>,
) -> __wasi_errno_t {
let nanos = match clock_id {
__WASI_CLOCK_MONOTONIC => {