mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-06 12:48:20 +00:00
Merge pull request #2442 from wasmerio/features-cell
Improved WasmPtr, added WasmCell
This commit is contained in:
149
lib/api/src/cell.rs
Normal file
149
lib/api/src/cell.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -253,6 +253,7 @@
|
|||||||
//! [wasmer-llvm]: https://docs.rs/wasmer-compiler-llvm/*/wasmer_compiler_llvm/
|
//! [wasmer-llvm]: https://docs.rs/wasmer-compiler-llvm/*/wasmer_compiler_llvm/
|
||||||
//! [wasmer-wasi]: https://docs.rs/wasmer-wasi/*/wasmer_wasi/
|
//! [wasmer-wasi]: https://docs.rs/wasmer-wasi/*/wasmer_wasi/
|
||||||
|
|
||||||
|
mod cell;
|
||||||
mod env;
|
mod env;
|
||||||
mod exports;
|
mod exports;
|
||||||
mod externals;
|
mod externals;
|
||||||
@@ -281,6 +282,7 @@ pub mod internals {
|
|||||||
pub use crate::externals::{WithEnv, WithoutEnv};
|
pub use crate::externals::{WithEnv, WithoutEnv};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use crate::cell::WasmCell;
|
||||||
pub use crate::env::{HostEnvInitError, LazyInit, WasmerEnv};
|
pub use crate::env::{HostEnvInitError, LazyInit, WasmerEnv};
|
||||||
pub use crate::exports::{ExportError, Exportable, Exports, ExportsIterator};
|
pub use crate::exports::{ExportError, Exportable, Exports, ExportsIterator};
|
||||||
pub use crate::externals::{
|
pub use crate::externals::{
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
//! Therefore, you should use this abstraction whenever possible to avoid memory
|
//! Therefore, you should use this abstraction whenever possible to avoid memory
|
||||||
//! related bugs when implementing an ABI.
|
//! related bugs when implementing an ABI.
|
||||||
|
|
||||||
|
use crate::cell::WasmCell;
|
||||||
use crate::{externals::Memory, FromToNativeWasmType};
|
use crate::{externals::Memory, FromToNativeWasmType};
|
||||||
use std::{cell::Cell, fmt, marker::PhantomData, mem};
|
use std::{cell::Cell, fmt, marker::PhantomData, mem};
|
||||||
use wasmer_types::ValueType;
|
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.
|
/// If you're unsure what that means, it likely does not apply to you.
|
||||||
/// This invariant will be enforced in the future.
|
/// This invariant will be enforced in the future.
|
||||||
#[inline]
|
#[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
|
if (self.offset as usize) + mem::size_of::<T>() > memory.size().bytes().0
|
||||||
|| mem::size_of::<T>() == 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,
|
memory.view::<u8>().as_ptr().add(self.offset as usize) as usize,
|
||||||
mem::align_of::<T>(),
|
mem::align_of::<T>(),
|
||||||
) as *const Cell<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
|
/// 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.
|
/// If you're unsure what that means, it likely does not apply to you.
|
||||||
/// This invariant will be enforced in the future.
|
/// This invariant will be enforced in the future.
|
||||||
#[inline]
|
#[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
|
// 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
|
// for any index, we will always result an aligned memory access
|
||||||
let item_size = mem::size_of::<T>();
|
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;
|
let memory_size = memory.size().bytes().0;
|
||||||
|
|
||||||
if (self.offset as usize) + (item_size * slice_full_len) > memory_size
|
if (self.offset as usize) + (item_size * slice_full_len) > memory_size
|
||||||
|| self.offset as usize >= memory_size
|
|| (self.offset as usize) >= memory_size
|
||||||
|| mem::size_of::<T>() == 0
|
|| item_size == 0
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
let cell_ptrs = unsafe {
|
||||||
unsafe {
|
|
||||||
let cell_ptr = align_pointer(
|
let cell_ptr = align_pointer(
|
||||||
memory.view::<u8>().as_ptr().add(self.offset as usize) as usize,
|
memory.view::<u8>().as_ptr().add(self.offset as usize) as usize,
|
||||||
mem::align_of::<T>(),
|
mem::align_of::<T>(),
|
||||||
) as *const Cell<T>;
|
) as *const Cell<T>;
|
||||||
let cell_ptrs = &std::slice::from_raw_parts(cell_ptr, slice_full_len)
|
&std::slice::from_raw_parts(cell_ptr, slice_full_len)[index as usize..slice_full_len]
|
||||||
[index as usize..slice_full_len];
|
};
|
||||||
Some(cell_ptrs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mutably dereference this `WasmPtr` getting a `&mut [Cell<T>]` allowing for
|
let wasm_cells = cell_ptrs
|
||||||
/// direct access to a `&mut [T]`.
|
.iter()
|
||||||
///
|
.map(|ptr| WasmCell::new(ptr))
|
||||||
/// # Safety
|
.collect::<Vec<_>>();
|
||||||
/// - This method does not do any aliasing checks: it's possible to create
|
Some(wasm_cells)
|
||||||
/// `&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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a UTF-8 string from the `WasmPtr` with the given length.
|
/// Get a UTF-8 string from the `WasmPtr` with the given length.
|
||||||
@@ -339,7 +291,7 @@ mod test {
|
|||||||
use crate::{Memory, MemoryType, Store};
|
use crate::{Memory, MemoryType, Store};
|
||||||
|
|
||||||
/// Ensure that memory accesses work on the edges of memory and that out of
|
/// 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]
|
#[test]
|
||||||
fn wasm_ptr_memory_bounds_checks_hold() {
|
fn wasm_ptr_memory_bounds_checks_hold() {
|
||||||
// create a memory
|
// create a memory
|
||||||
@@ -352,29 +304,23 @@ mod test {
|
|||||||
let start_wasm_ptr_array: WasmPtr<u8, Array> = WasmPtr::new(0);
|
let start_wasm_ptr_array: WasmPtr<u8, Array> = WasmPtr::new(0);
|
||||||
|
|
||||||
assert!(start_wasm_ptr.deref(&memory).is_some());
|
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!(start_wasm_ptr_array.deref(&memory, 0, 0).is_some());
|
||||||
assert!(unsafe { start_wasm_ptr_array.get_utf8_str(&memory, 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!(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!(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
|
// 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 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);
|
let end_wasm_ptr: WasmPtr<u8> = WasmPtr::new(last_valid_address_for_u8);
|
||||||
assert!(end_wasm_ptr.deref(&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_array: WasmPtr<u8, Array> = WasmPtr::new(last_valid_address_for_u8);
|
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!(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] =
|
let invalid_idx_len_combos: [(u32, u32); 3] =
|
||||||
[(last_valid_address_for_u8 + 1, 0), (0, 2), (1, 1)];
|
[(last_valid_address_for_u8 + 1, 0), (0, 2), (1, 1)];
|
||||||
for &(idx, len) in invalid_idx_len_combos.iter() {
|
for &(idx, len) in invalid_idx_len_combos.iter() {
|
||||||
assert!(end_wasm_ptr_array.deref(&memory, idx, len).is_none());
|
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!(unsafe { end_wasm_ptr_array.get_utf8_str(&memory, 2).is_none() });
|
||||||
assert!(end_wasm_ptr_array.get_utf8_string(&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 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);
|
let end_wasm_ptr: WasmPtr<u32> = WasmPtr::new(last_valid_address_for_u32);
|
||||||
assert!(end_wasm_ptr.deref(&memory).is_some());
|
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!(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] = [
|
let end_wasm_ptr_oob_array: [WasmPtr<u32>; 4] = [
|
||||||
WasmPtr::new(last_valid_address_for_u32 + 1),
|
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() {
|
for oob_end_ptr in end_wasm_ptr_oob_array.iter() {
|
||||||
assert!(oob_end_ptr.deref(&memory).is_none());
|
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);
|
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!(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] =
|
let invalid_idx_len_combos: [(u32, u32); 3] =
|
||||||
[(last_valid_address_for_u32 + 1, 0), (0, 2), (1, 1)];
|
[(last_valid_address_for_u32 + 1, 0), (0, 2), (1, 1)];
|
||||||
for &(idx, len) in invalid_idx_len_combos.iter() {
|
for &(idx, len) in invalid_idx_len_combos.iter() {
|
||||||
assert!(end_wasm_ptr_array.deref(&memory, idx, len).is_none());
|
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] = [
|
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() {
|
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!(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!(oob_end_array_ptr.deref(&memory, 1, 0).is_none());
|
||||||
assert!(unsafe { oob_end_array_ptr.deref_mut(&memory, 1, 0).is_none() });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
44
lib/emscripten/src/env/unix/mod.rs
vendored
44
lib/emscripten/src/env/unix/mod.rs
vendored
@@ -3,7 +3,6 @@ use libc::{
|
|||||||
c_int, getenv, getgrnam as libc_getgrnam, getpwnam as libc_getpwnam, putenv, setenv, sysconf,
|
c_int, getenv, getgrnam as libc_getgrnam, getpwnam as libc_getpwnam, putenv, setenv, sysconf,
|
||||||
unsetenv,
|
unsetenv,
|
||||||
};
|
};
|
||||||
use std::cell::Cell;
|
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::os::raw::c_char;
|
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 string_on_guest: WasmPtr<c_char, Array> = call_malloc_with_cast(ctx, bytes.len() as _);
|
||||||
let memory = ctx.memory(0);
|
let memory = ctx.memory(0);
|
||||||
|
|
||||||
let writer = unsafe {
|
let writer = string_on_guest.deref(&memory, 0, bytes.len() as _).unwrap();
|
||||||
string_on_guest
|
|
||||||
.deref_mut(&memory, 0, bytes.len() as _)
|
|
||||||
.unwrap()
|
|
||||||
};
|
|
||||||
for (i, byte) in bytes.iter().enumerate() {
|
for (i, byte) in bytes.iter().enumerate() {
|
||||||
writer[i].set(*byte as _);
|
writer[i].set(*byte as _);
|
||||||
}
|
}
|
||||||
@@ -174,21 +169,23 @@ pub fn _getaddrinfo(
|
|||||||
use libc::{addrinfo, freeaddrinfo};
|
use libc::{addrinfo, freeaddrinfo};
|
||||||
debug!("emscripten::_getaddrinfo");
|
debug!("emscripten::_getaddrinfo");
|
||||||
let memory = ctx.memory(0);
|
let memory = ctx.memory(0);
|
||||||
debug!(" => node = {}", unsafe {
|
debug!(" => node = {}", {
|
||||||
node_ptr
|
node_ptr
|
||||||
.deref(&memory)
|
.deref(&memory)
|
||||||
.map(|np| {
|
.map(|_np| {
|
||||||
std::ffi::CStr::from_ptr(np as *const Cell<c_char> as *const c_char)
|
unimplemented!();
|
||||||
.to_string_lossy()
|
// 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"))
|
.unwrap_or(std::borrow::Cow::Borrowed("null"))
|
||||||
});
|
});
|
||||||
debug!(" => server_str = {}", unsafe {
|
debug!(" => server_str = {}", {
|
||||||
service_str_ptr
|
service_str_ptr
|
||||||
.deref(&memory)
|
.deref(&memory)
|
||||||
.map(|np| {
|
.map(|_np| {
|
||||||
std::ffi::CStr::from_ptr(np as *const Cell<c_char> as *const c_char)
|
unimplemented!();
|
||||||
.to_string_lossy()
|
// 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"))
|
.unwrap_or(std::borrow::Cow::Borrowed("null"))
|
||||||
});
|
});
|
||||||
@@ -212,13 +209,17 @@ pub fn _getaddrinfo(
|
|||||||
// allocate equivalent memory for res_val_ptr
|
// allocate equivalent memory for res_val_ptr
|
||||||
let result = unsafe {
|
let result = unsafe {
|
||||||
libc::getaddrinfo(
|
libc::getaddrinfo(
|
||||||
(node_ptr
|
(node_ptr.deref(&memory).map(|_m| {
|
||||||
.deref(&memory)
|
unimplemented!();
|
||||||
.map(|m| m as *const Cell<c_char> as *const c_char))
|
//m as *const Cell<c_char> as *const c_char
|
||||||
|
}))
|
||||||
.unwrap_or(std::ptr::null()),
|
.unwrap_or(std::ptr::null()),
|
||||||
service_str_ptr
|
service_str_ptr
|
||||||
.deref(&memory)
|
.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()),
|
.unwrap_or(std::ptr::null()),
|
||||||
hints
|
hints
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@@ -246,7 +247,7 @@ pub fn _getaddrinfo(
|
|||||||
|
|
||||||
// connect list
|
// connect list
|
||||||
if let Some(prev_guest) = previous_guest_node {
|
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;
|
pg.ai_next = current_guest_node_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,7 +259,7 @@ pub fn _getaddrinfo(
|
|||||||
let host_sockaddr_ptr = (*current_host_node).ai_addr;
|
let host_sockaddr_ptr = (*current_host_node).ai_addr;
|
||||||
let guest_sockaddr_ptr: WasmPtr<EmSockAddr> =
|
let guest_sockaddr_ptr: WasmPtr<EmSockAddr> =
|
||||||
call_malloc_with_cast(ctx, host_addrlen as _);
|
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_family = (*host_sockaddr_ptr).sa_family as i16;
|
||||||
guest_sockaddr.sa_data = (*host_sockaddr_ptr).sa_data;
|
guest_sockaddr.sa_data = (*host_sockaddr_ptr).sa_data;
|
||||||
@@ -287,8 +288,7 @@ pub fn _getaddrinfo(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut current_guest_node =
|
let mut current_guest_node = current_guest_node_ptr.deref(&memory).unwrap().get_mut();
|
||||||
current_guest_node_ptr.deref_mut(&memory).unwrap().get_mut();
|
|
||||||
current_guest_node.ai_flags = (*current_host_node).ai_flags;
|
current_guest_node.ai_flags = (*current_host_node).ai_flags;
|
||||||
current_guest_node.ai_family = (*current_host_node).ai_family;
|
current_guest_node.ai_family = (*current_host_node).ai_family;
|
||||||
current_guest_node.ai_socktype = (*current_host_node).ai_socktype;
|
current_guest_node.ai_socktype = (*current_host_node).ai_socktype;
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
// don't want to warn about unusued code here
|
// don't want to warn about unusued code here
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::{cell::Cell, fmt};
|
use std::fmt;
|
||||||
pub use wasmer::{Array, FromToNativeWasmType, Memory, ValueType};
|
pub use wasmer::{Array, FromToNativeWasmType, Memory, ValueType, WasmCell};
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct WasmPtr<T: Copy, Ty = wasmer::Item>(wasmer::WasmPtr<T, Ty>);
|
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> {
|
impl<T: Copy + ValueType> WasmPtr<T, wasmer::Item> {
|
||||||
#[inline(always)]
|
#[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 {
|
if self.0.offset() == 0 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
self.0.deref(memory)
|
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> {
|
impl<T: Copy + ValueType> WasmPtr<T, wasmer::Array> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn deref<'a>(self, memory: &'a Memory, index: u32, length: u32) -> Option<&'a [Cell<T>]> {
|
pub fn deref<'a>(
|
||||||
if self.0.offset() == 0 {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
self.0.deref(memory, index, length)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub unsafe fn deref_mut<'a>(
|
|
||||||
self,
|
self,
|
||||||
memory: &'a Memory,
|
memory: &'a Memory,
|
||||||
index: u32,
|
index: u32,
|
||||||
length: u32,
|
length: u32,
|
||||||
) -> Option<&'a mut [Cell<T>]> {
|
) -> Option<Vec<WasmCell<'a, T>>> {
|
||||||
if self.0.offset() == 0 {
|
if self.0.offset() == 0 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
self.0.deref_mut(memory, index, length)
|
self.0.deref(memory, index, length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -633,7 +633,7 @@ pub fn ___syscall102(ctx: &EmEnv, _which: c_int, mut varargs: VarArgs) -> c_int
|
|||||||
address.deref(&memory).unwrap().get(),
|
address.deref(&memory).unwrap().get(),
|
||||||
address_len.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 address_len_addr: socklen_t = 0;
|
||||||
|
|
||||||
let mut host_address: sockaddr = sockaddr {
|
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(),
|
sa_len: Default::default(),
|
||||||
};
|
};
|
||||||
let fd = unsafe { accept(socket, &mut host_address, address_len_addr) };
|
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_family = host_address.sa_family as _;
|
||||||
address_addr.sa_data = host_address.sa_data;
|
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 socket: i32 = socket_varargs.get(ctx);
|
||||||
let address: WasmPtr<EmSockAddr> = socket_varargs.get(ctx);
|
let address: WasmPtr<EmSockAddr> = socket_varargs.get(ctx);
|
||||||
let address_len: WasmPtr<u32> = 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 {
|
let mut sock_addr_host: sockaddr = sockaddr {
|
||||||
sa_family: Default::default(),
|
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
|
// 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_family = sock_addr_host.sa_family as _;
|
||||||
address_mut.sa_data = sock_addr_host.sa_data;
|
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 timeout: i32 = varargs.get(ctx);
|
||||||
let memory = ctx.memory(0);
|
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 {
|
let ret = unsafe {
|
||||||
libc::poll(
|
libc::poll(
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::lib::std::cell::Cell;
|
use crate::lib::std::cell::Cell;
|
||||||
use crate::lib::std::marker::PhantomData;
|
use crate::lib::std::marker::PhantomData;
|
||||||
use crate::lib::std::ops::Deref;
|
use crate::lib::std::ops::Deref;
|
||||||
|
use crate::lib::std::ops::{Bound, RangeBounds};
|
||||||
use crate::lib::std::slice;
|
use crate::lib::std::slice;
|
||||||
use crate::lib::std::sync::atomic::{
|
use crate::lib::std::sync::atomic::{
|
||||||
AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicU16, AtomicU32, AtomicU64, AtomicU8,
|
AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicU16, AtomicU32, AtomicU64, AtomicU8,
|
||||||
@@ -48,6 +49,8 @@ impl Atomicity for NonAtomically {}
|
|||||||
/// A view into a memory.
|
/// A view into a memory.
|
||||||
pub struct MemoryView<'a, T: 'a, A = NonAtomically> {
|
pub struct MemoryView<'a, T: 'a, A = NonAtomically> {
|
||||||
ptr: *mut T,
|
ptr: *mut T,
|
||||||
|
// Note: the length is in the terms of `size::<T>()`.
|
||||||
|
// The total length in memory is `size::<T>() * length`.
|
||||||
length: usize,
|
length: usize,
|
||||||
_phantom: PhantomData<(&'a [Cell<T>], A)>,
|
_phantom: PhantomData<(&'a [Cell<T>], A)>,
|
||||||
}
|
}
|
||||||
@@ -64,6 +67,50 @@ where
|
|||||||
_phantom: PhantomData,
|
_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
|
||||||
|
/// module’s 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> {
|
impl<'a, T: Atomic> MemoryView<'a, T> {
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
//! if memory access failed
|
//! if memory access failed
|
||||||
|
|
||||||
use crate::syscalls::types::{__wasi_errno_t, __WASI_EFAULT};
|
use crate::syscalls::types::{__wasi_errno_t, __WASI_EFAULT};
|
||||||
use std::{cell::Cell, fmt};
|
use std::fmt;
|
||||||
pub use wasmer::{Array, FromToNativeWasmType, Item, Memory, ValueType, WasmPtr as BaseWasmPtr};
|
pub use wasmer::{
|
||||||
|
Array, FromToNativeWasmType, Item, Memory, ValueType, WasmCell, WasmPtr as BaseWasmPtr,
|
||||||
|
};
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct WasmPtr<T: Copy, Ty = Item>(BaseWasmPtr<T, Ty>);
|
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> {
|
impl<T: Copy + ValueType> WasmPtr<T, Item> {
|
||||||
#[inline(always)]
|
#[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)
|
self.0.deref(memory).ok_or(__WASI_EFAULT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,7 +77,7 @@ impl<T: Copy + ValueType> WasmPtr<T, Array> {
|
|||||||
memory: &'a Memory,
|
memory: &'a Memory,
|
||||||
index: u32,
|
index: u32,
|
||||||
length: 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)
|
self.0.deref(memory, index, length).ok_or(__WASI_EFAULT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,11 +27,10 @@ use crate::{
|
|||||||
WasiEnv, WasiError,
|
WasiEnv, WasiError,
|
||||||
};
|
};
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::cell::Cell;
|
|
||||||
use std::convert::{Infallible, TryInto};
|
use std::convert::{Infallible, TryInto};
|
||||||
use std::io::{self, Read, Seek, Write};
|
use std::io::{self, Read, Seek, Write};
|
||||||
use tracing::{debug, trace};
|
use tracing::{debug, trace};
|
||||||
use wasmer::{Memory, RuntimeError, Value};
|
use wasmer::{Memory, RuntimeError, Value, WasmCell};
|
||||||
|
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
target_os = "freebsd",
|
target_os = "freebsd",
|
||||||
@@ -47,7 +46,7 @@ pub use windows::*;
|
|||||||
fn write_bytes_inner<T: Write>(
|
fn write_bytes_inner<T: Write>(
|
||||||
mut write_loc: T,
|
mut write_loc: T,
|
||||||
memory: &Memory,
|
memory: &Memory,
|
||||||
iovs_arr_cell: &[Cell<__wasi_ciovec_t>],
|
iovs_arr_cell: &[WasmCell<__wasi_ciovec_t>],
|
||||||
) -> Result<u32, __wasi_errno_t> {
|
) -> Result<u32, __wasi_errno_t> {
|
||||||
let mut bytes_written = 0;
|
let mut bytes_written = 0;
|
||||||
for iov in iovs_arr_cell {
|
for iov in iovs_arr_cell {
|
||||||
@@ -66,7 +65,7 @@ fn write_bytes_inner<T: Write>(
|
|||||||
fn write_bytes<T: Write>(
|
fn write_bytes<T: Write>(
|
||||||
mut write_loc: T,
|
mut write_loc: T,
|
||||||
memory: &Memory,
|
memory: &Memory,
|
||||||
iovs_arr_cell: &[Cell<__wasi_ciovec_t>],
|
iovs_arr_cell: &[WasmCell<__wasi_ciovec_t>],
|
||||||
) -> Result<u32, __wasi_errno_t> {
|
) -> Result<u32, __wasi_errno_t> {
|
||||||
let result = write_bytes_inner(&mut write_loc, memory, iovs_arr_cell);
|
let result = write_bytes_inner(&mut write_loc, memory, iovs_arr_cell);
|
||||||
write_loc.flush();
|
write_loc.flush();
|
||||||
@@ -76,16 +75,27 @@ fn write_bytes<T: Write>(
|
|||||||
fn read_bytes<T: Read>(
|
fn read_bytes<T: Read>(
|
||||||
mut reader: T,
|
mut reader: T,
|
||||||
memory: &Memory,
|
memory: &Memory,
|
||||||
iovs_arr_cell: &[Cell<__wasi_iovec_t>],
|
iovs_arr_cell: &[WasmCell<__wasi_iovec_t>],
|
||||||
) -> Result<u32, __wasi_errno_t> {
|
) -> Result<u32, __wasi_errno_t> {
|
||||||
let mut bytes_read = 0;
|
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 {
|
for iov in iovs_arr_cell {
|
||||||
let iov_inner = iov.get();
|
let iov_inner = iov.get();
|
||||||
let bytes = WasmPtr::<u8, Array>::new(iov_inner.buf).deref(memory, 0, iov_inner.buf_len)?;
|
raw_bytes.clear();
|
||||||
let mut raw_bytes: &mut [u8] =
|
raw_bytes.resize(iov_inner.buf_len as usize, 0);
|
||||||
unsafe { &mut *(bytes as *const [_] as *mut [_] as *mut [u8]) };
|
bytes_read += reader.read(&mut raw_bytes).map_err(|_| __WASI_EIO)? as u32;
|
||||||
bytes_read += reader.read(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)
|
Ok(bytes_read)
|
||||||
}
|
}
|
||||||
@@ -660,7 +670,7 @@ pub fn fd_pread(
|
|||||||
if let Some(ref mut stdin) =
|
if let Some(ref mut stdin) =
|
||||||
wasi_try!(state.fs.stdin_mut().map_err(WasiFsError::into_wasi_err))
|
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 {
|
} else {
|
||||||
return __WASI_EBADF;
|
return __WASI_EBADF;
|
||||||
}
|
}
|
||||||
@@ -687,7 +697,7 @@ pub fn fd_pread(
|
|||||||
h.seek(std::io::SeekFrom::Start(offset as u64)).ok(),
|
h.seek(std::io::SeekFrom::Start(offset as u64)).ok(),
|
||||||
__WASI_EIO
|
__WASI_EIO
|
||||||
);
|
);
|
||||||
wasi_try!(read_bytes(h, memory, iov_cells))
|
wasi_try!(read_bytes(h, memory, &iov_cells))
|
||||||
} else {
|
} else {
|
||||||
return __WASI_EINVAL;
|
return __WASI_EINVAL;
|
||||||
}
|
}
|
||||||
@@ -695,7 +705,7 @@ pub fn fd_pread(
|
|||||||
Kind::Dir { .. } | Kind::Root { .. } => return __WASI_EISDIR,
|
Kind::Dir { .. } | Kind::Root { .. } => return __WASI_EISDIR,
|
||||||
Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_pread"),
|
Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_pread"),
|
||||||
Kind::Buffer { buffer } => {
|
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) =
|
if let Some(ref mut stdout) =
|
||||||
wasi_try!(state.fs.stdout_mut().map_err(WasiFsError::into_wasi_err))
|
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 {
|
} else {
|
||||||
return __WASI_EBADF;
|
return __WASI_EBADF;
|
||||||
}
|
}
|
||||||
@@ -818,7 +828,7 @@ pub fn fd_pwrite(
|
|||||||
if let Some(ref mut stderr) =
|
if let Some(ref mut stderr) =
|
||||||
wasi_try!(state.fs.stderr_mut().map_err(WasiFsError::into_wasi_err))
|
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 {
|
} else {
|
||||||
return __WASI_EBADF;
|
return __WASI_EBADF;
|
||||||
}
|
}
|
||||||
@@ -839,7 +849,7 @@ pub fn fd_pwrite(
|
|||||||
Kind::File { handle, .. } => {
|
Kind::File { handle, .. } => {
|
||||||
if let Some(handle) = handle {
|
if let Some(handle) = handle {
|
||||||
handle.seek(std::io::SeekFrom::Start(offset as u64));
|
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 {
|
} else {
|
||||||
return __WASI_EINVAL;
|
return __WASI_EINVAL;
|
||||||
}
|
}
|
||||||
@@ -853,7 +863,7 @@ pub fn fd_pwrite(
|
|||||||
wasi_try!(write_bytes(
|
wasi_try!(write_bytes(
|
||||||
&mut buffer[(offset as usize)..],
|
&mut buffer[(offset as usize)..],
|
||||||
memory,
|
memory,
|
||||||
iovs_arr_cell
|
&iovs_arr_cell
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -895,7 +905,7 @@ pub fn fd_read(
|
|||||||
if let Some(ref mut stdin) =
|
if let Some(ref mut stdin) =
|
||||||
wasi_try!(state.fs.stdin_mut().map_err(WasiFsError::into_wasi_err))
|
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 {
|
} else {
|
||||||
return __WASI_EBADF;
|
return __WASI_EBADF;
|
||||||
}
|
}
|
||||||
@@ -917,7 +927,7 @@ pub fn fd_read(
|
|||||||
Kind::File { handle, .. } => {
|
Kind::File { handle, .. } => {
|
||||||
if let Some(handle) = handle {
|
if let Some(handle) = handle {
|
||||||
handle.seek(std::io::SeekFrom::Start(offset as u64));
|
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 {
|
} else {
|
||||||
return __WASI_EINVAL;
|
return __WASI_EINVAL;
|
||||||
}
|
}
|
||||||
@@ -928,7 +938,7 @@ pub fn fd_read(
|
|||||||
}
|
}
|
||||||
Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_read"),
|
Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_read"),
|
||||||
Kind::Buffer { buffer } => {
|
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) =
|
if let Some(ref mut stdout) =
|
||||||
wasi_try!(state.fs.stdout_mut().map_err(WasiFsError::into_wasi_err))
|
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 {
|
} else {
|
||||||
return __WASI_EBADF;
|
return __WASI_EBADF;
|
||||||
}
|
}
|
||||||
@@ -1275,7 +1285,7 @@ pub fn fd_write(
|
|||||||
if let Some(ref mut stderr) =
|
if let Some(ref mut stderr) =
|
||||||
wasi_try!(state.fs.stderr_mut().map_err(WasiFsError::into_wasi_err))
|
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 {
|
} else {
|
||||||
return __WASI_EBADF;
|
return __WASI_EBADF;
|
||||||
}
|
}
|
||||||
@@ -1295,7 +1305,7 @@ pub fn fd_write(
|
|||||||
Kind::File { handle, .. } => {
|
Kind::File { handle, .. } => {
|
||||||
if let Some(handle) = handle {
|
if let Some(handle) = handle {
|
||||||
handle.seek(std::io::SeekFrom::Start(offset as u64));
|
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 {
|
} else {
|
||||||
return __WASI_EINVAL;
|
return __WASI_EINVAL;
|
||||||
}
|
}
|
||||||
@@ -1306,7 +1316,7 @@ pub fn fd_write(
|
|||||||
}
|
}
|
||||||
Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_write"),
|
Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_write"),
|
||||||
Kind::Buffer { buffer } => {
|
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
|
/// A pointer to a buffer where the random bytes will be written
|
||||||
/// - `size_t buf_len`
|
/// - `size_t buf_len`
|
||||||
/// The number of bytes that will be written
|
/// 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);
|
debug!("wasi::random_get buf_len: {}", buf_len);
|
||||||
let memory = env.memory();
|
let memory = env.memory();
|
||||||
|
let mut u8_buffer = vec![0; buf_len as usize];
|
||||||
let buf = wasi_try!(buf.deref(memory, 0, buf_len));
|
let res = getrandom::getrandom(&mut u8_buffer);
|
||||||
|
|
||||||
let res = unsafe {
|
|
||||||
let u8_buffer = &mut *(buf as *const [_] as *mut [_] as *mut [u8]);
|
|
||||||
getrandom::getrandom(u8_buffer)
|
|
||||||
};
|
|
||||||
match res {
|
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,
|
Err(_) => __WASI_EIO,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ use libc::{
|
|||||||
clock_getres, clock_gettime, timespec, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID,
|
clock_getres, clock_gettime, timespec, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID,
|
||||||
CLOCK_REALTIME, CLOCK_THREAD_CPUTIME_ID,
|
CLOCK_REALTIME, CLOCK_THREAD_CPUTIME_ID,
|
||||||
};
|
};
|
||||||
use std::cell::Cell;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use wasmer::WasmCell;
|
||||||
|
|
||||||
pub fn platform_clock_res_get(
|
pub fn platform_clock_res_get(
|
||||||
clock_id: __wasi_clockid_t,
|
clock_id: __wasi_clockid_t,
|
||||||
resolution: &Cell<__wasi_timestamp_t>,
|
resolution: WasmCell<__wasi_timestamp_t>,
|
||||||
) -> __wasi_errno_t {
|
) -> __wasi_errno_t {
|
||||||
let unix_clock_id = match clock_id {
|
let unix_clock_id = match clock_id {
|
||||||
__WASI_CLOCK_MONOTONIC => CLOCK_MONOTONIC,
|
__WASI_CLOCK_MONOTONIC => CLOCK_MONOTONIC,
|
||||||
@@ -36,7 +36,7 @@ pub fn platform_clock_res_get(
|
|||||||
pub fn platform_clock_time_get(
|
pub fn platform_clock_time_get(
|
||||||
clock_id: __wasi_clockid_t,
|
clock_id: __wasi_clockid_t,
|
||||||
precision: __wasi_timestamp_t,
|
precision: __wasi_timestamp_t,
|
||||||
time: &Cell<__wasi_timestamp_t>,
|
time: WasmCell<__wasi_timestamp_t>,
|
||||||
) -> __wasi_errno_t {
|
) -> __wasi_errno_t {
|
||||||
let unix_clock_id = match clock_id {
|
let unix_clock_id = match clock_id {
|
||||||
__WASI_CLOCK_MONOTONIC => CLOCK_MONOTONIC,
|
__WASI_CLOCK_MONOTONIC => CLOCK_MONOTONIC,
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::syscalls::types::*;
|
use crate::syscalls::types::*;
|
||||||
use std::cell::Cell;
|
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
use wasmer::WasmCell;
|
||||||
|
|
||||||
pub fn platform_clock_res_get(
|
pub fn platform_clock_res_get(
|
||||||
clock_id: __wasi_clockid_t,
|
clock_id: __wasi_clockid_t,
|
||||||
resolution: &Cell<__wasi_timestamp_t>,
|
resolution: WasmCell<__wasi_timestamp_t>,
|
||||||
) -> __wasi_errno_t {
|
) -> __wasi_errno_t {
|
||||||
let resolution_val = match clock_id {
|
let resolution_val = match clock_id {
|
||||||
// resolution of monotonic clock at 10ms, from:
|
// resolution of monotonic clock at 10ms, from:
|
||||||
@@ -27,7 +27,7 @@ pub fn platform_clock_res_get(
|
|||||||
pub fn platform_clock_time_get(
|
pub fn platform_clock_time_get(
|
||||||
clock_id: __wasi_clockid_t,
|
clock_id: __wasi_clockid_t,
|
||||||
precision: __wasi_timestamp_t,
|
precision: __wasi_timestamp_t,
|
||||||
time: &Cell<__wasi_timestamp_t>,
|
time: WasmCell<__wasi_timestamp_t>,
|
||||||
) -> __wasi_errno_t {
|
) -> __wasi_errno_t {
|
||||||
let nanos = match clock_id {
|
let nanos = match clock_id {
|
||||||
__WASI_CLOCK_MONOTONIC => {
|
__WASI_CLOCK_MONOTONIC => {
|
||||||
|
|||||||
Reference in New Issue
Block a user