mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-07 21:28:21 +00:00
Fixed a memory corruption issue with JS memory operations that were reusing invalid views
This commit is contained in:
8
lib/api/src/js/externals/function.rs
vendored
8
lib/api/src/js/externals/function.rs
vendored
@@ -115,7 +115,7 @@ impl Function {
|
||||
let wrapped_func: JsValue = match function_type.results().len() {
|
||||
0 => Closure::wrap(Box::new(move |args: &Array| {
|
||||
let mut store: StoreMut = unsafe { StoreMut::from_raw(raw_store as _) };
|
||||
let mut env: FunctionEnvMut<T> = raw_env.clone().into_mut(&mut store);
|
||||
let env: FunctionEnvMut<T> = raw_env.clone().into_mut(&mut store);
|
||||
let wasm_arguments = function_type
|
||||
.params()
|
||||
.iter()
|
||||
@@ -129,7 +129,7 @@ impl Function {
|
||||
.into_js_value(),
|
||||
1 => Closure::wrap(Box::new(move |args: &Array| {
|
||||
let mut store: StoreMut = unsafe { StoreMut::from_raw(raw_store as _) };
|
||||
let mut env: FunctionEnvMut<T> = raw_env.clone().into_mut(&mut store);
|
||||
let env: FunctionEnvMut<T> = raw_env.clone().into_mut(&mut store);
|
||||
let wasm_arguments = function_type
|
||||
.params()
|
||||
.iter()
|
||||
@@ -143,7 +143,7 @@ impl Function {
|
||||
.into_js_value(),
|
||||
_n => Closure::wrap(Box::new(move |args: &Array| {
|
||||
let mut store: StoreMut = unsafe { StoreMut::from_raw(raw_store as _) };
|
||||
let mut env: FunctionEnvMut<T> = raw_env.clone().into_mut(&mut store);
|
||||
let env: FunctionEnvMut<T> = raw_env.clone().into_mut(&mut store);
|
||||
let wasm_arguments = function_type
|
||||
.params()
|
||||
.iter()
|
||||
@@ -509,7 +509,7 @@ mod inner {
|
||||
use super::RuntimeError;
|
||||
use super::VMFunctionBody;
|
||||
use crate::js::function_env::{FunctionEnvMut, VMFunctionEnvironment};
|
||||
use crate::js::store::{AsStoreMut, InternalStoreHandle, StoreHandle, StoreInner, StoreMut};
|
||||
use crate::js::store::{AsStoreMut, InternalStoreHandle, StoreHandle, StoreMut};
|
||||
use crate::js::FunctionEnv;
|
||||
use crate::js::NativeWasmTypeInto;
|
||||
use std::array::TryFromSliceError;
|
||||
|
||||
184
lib/api/src/js/externals/memory.rs
vendored
184
lib/api/src/js/externals/memory.rs
vendored
@@ -3,15 +3,17 @@ use crate::js::exports::{ExportError, Exportable};
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle, StoreObjects};
|
||||
use crate::js::{MemoryAccessError, MemoryType};
|
||||
use std::convert::TryInto;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::slice;
|
||||
use thiserror::Error;
|
||||
use tracing::warn;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen::JsCast;
|
||||
use wasmer_types::{Bytes, Pages};
|
||||
use wasmer_types::Pages;
|
||||
|
||||
use super::MemoryView;
|
||||
|
||||
/// Error type describing things that can go wrong when operating on Wasm Memories.
|
||||
#[derive(Error, Debug, Clone, PartialEq, Hash)]
|
||||
@@ -79,8 +81,6 @@ extern "C" {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Memory {
|
||||
pub(crate) handle: StoreHandle<VMMemory>,
|
||||
#[allow(dead_code)]
|
||||
view: js_sys::Uint8Array,
|
||||
}
|
||||
|
||||
unsafe impl Send for Memory {}
|
||||
@@ -132,52 +132,10 @@ impl Memory {
|
||||
self.handle.get(store.as_store_ref().objects()).ty
|
||||
}
|
||||
|
||||
/// Returns the pointer to the raw bytes of the `Memory`.
|
||||
#[doc(hidden)]
|
||||
pub fn data_ptr(&self) -> *mut u8 {
|
||||
unimplemented!("direct data pointer access is not possible in JavaScript");
|
||||
}
|
||||
|
||||
/// Returns the size (in bytes) of the `Memory`.
|
||||
pub fn data_size(&self, store: &impl AsStoreRef) -> u64 {
|
||||
js_sys::Reflect::get(
|
||||
&self
|
||||
.handle
|
||||
.get(store.as_store_ref().objects())
|
||||
.memory
|
||||
.buffer(),
|
||||
&"byteLength".into(),
|
||||
)
|
||||
.unwrap()
|
||||
.as_f64()
|
||||
.unwrap() as _
|
||||
}
|
||||
|
||||
/// Returns the size (in [`Pages`]) of the `Memory`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
|
||||
///
|
||||
/// assert_eq!(m.size(), Pages(1));
|
||||
/// ```
|
||||
pub fn size(&self, store: &impl AsStoreRef) -> Pages {
|
||||
let bytes = js_sys::Reflect::get(
|
||||
&self
|
||||
.handle
|
||||
.get(store.as_store_ref().objects())
|
||||
.memory
|
||||
.buffer(),
|
||||
&"byteLength".into(),
|
||||
)
|
||||
.unwrap()
|
||||
.as_f64()
|
||||
.unwrap() as u64;
|
||||
Bytes(bytes as usize).try_into().unwrap()
|
||||
/// Creates a view into the memory that then allows for
|
||||
/// read and write
|
||||
pub fn view(&self, store: &impl AsStoreRef) -> MemoryView {
|
||||
MemoryView::new(self, store)
|
||||
}
|
||||
|
||||
/// Grow memory by the specified amount of WebAssembly [`Pages`] and return
|
||||
@@ -219,12 +177,13 @@ impl Memory {
|
||||
IntoPages: Into<Pages>,
|
||||
{
|
||||
let pages = delta.into();
|
||||
warn!("memory grow {}", pages.0);
|
||||
let js_memory = &self.handle.get_mut(store.objects_mut()).memory;
|
||||
let our_js_memory: &JSMemory = JsCast::unchecked_from_js_ref(js_memory);
|
||||
let new_pages = our_js_memory.grow(pages.0).map_err(|err| {
|
||||
if err.is_instance_of::<js_sys::RangeError>() {
|
||||
MemoryError::CouldNotGrow {
|
||||
current: self.size(&store.as_store_ref()),
|
||||
current: self.view(&store.as_store_ref()).size(),
|
||||
attempted_delta: pages,
|
||||
}
|
||||
} else {
|
||||
@@ -234,30 +193,9 @@ impl Memory {
|
||||
Ok(Pages(new_pages))
|
||||
}
|
||||
|
||||
/// Used by tests
|
||||
#[doc(hidden)]
|
||||
pub fn uint8view(&self, store: &impl AsStoreRef) -> js_sys::Uint8Array {
|
||||
js_sys::Uint8Array::new(
|
||||
&self
|
||||
.handle
|
||||
.get(store.as_store_ref().objects())
|
||||
.memory
|
||||
.buffer(),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn buffer<'a>(&'a self, _store: &'a impl AsStoreRef) -> MemoryBuffer<'a> {
|
||||
MemoryBuffer {
|
||||
base: &self.view as *const _ as *mut _,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_vm_export(store: &mut impl AsStoreMut, vm_memory: VMMemory) -> Self {
|
||||
let view = js_sys::Uint8Array::new(&vm_memory.memory.buffer());
|
||||
Self {
|
||||
handle: StoreHandle::new(store.objects_mut(), vm_memory),
|
||||
view,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,108 +203,13 @@ impl Memory {
|
||||
store: &mut impl AsStoreMut,
|
||||
internal: InternalStoreHandle<VMMemory>,
|
||||
) -> Self {
|
||||
let view =
|
||||
js_sys::Uint8Array::new(&internal.get(store.as_store_ref().objects()).memory.buffer());
|
||||
Self {
|
||||
handle: unsafe {
|
||||
StoreHandle::from_internal(store.as_store_ref().objects().id(), internal)
|
||||
},
|
||||
view,
|
||||
}
|
||||
}
|
||||
|
||||
/// Safely reads bytes from the memory at the given offset.
|
||||
///
|
||||
/// The full buffer will be filled, otherwise a `MemoryAccessError` is returned
|
||||
/// to indicate an out-of-bounds access.
|
||||
///
|
||||
/// This method is guaranteed to be safe (from the host side) in the face of
|
||||
/// concurrent writes.
|
||||
pub fn read(
|
||||
&self,
|
||||
_store: &impl AsStoreRef,
|
||||
offset: u64,
|
||||
data: &mut [u8],
|
||||
) -> Result<(), MemoryAccessError> {
|
||||
let view = &self.view;
|
||||
let offset: u32 = offset.try_into().map_err(|_| MemoryAccessError::Overflow)?;
|
||||
let len: u32 = data
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(|_| MemoryAccessError::Overflow)?;
|
||||
let end = offset.checked_add(len).ok_or(MemoryAccessError::Overflow)?;
|
||||
if end > view.length() {
|
||||
Err(MemoryAccessError::HeapOutOfBounds)?;
|
||||
}
|
||||
view.subarray(offset, end).copy_to(data);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Safely reads bytes from the memory at the given offset.
|
||||
///
|
||||
/// This method is similar to `read` but allows reading into an
|
||||
/// uninitialized buffer. An initialized view of the buffer is returned.
|
||||
///
|
||||
/// The full buffer will be filled, otherwise a `MemoryAccessError` is returned
|
||||
/// to indicate an out-of-bounds access.
|
||||
///
|
||||
/// This method is guaranteed to be safe (from the host side) in the face of
|
||||
/// concurrent writes.
|
||||
pub fn read_uninit<'a>(
|
||||
&self,
|
||||
_store: &impl AsStoreRef,
|
||||
offset: u64,
|
||||
buf: &'a mut [MaybeUninit<u8>],
|
||||
) -> Result<&'a mut [u8], MemoryAccessError> {
|
||||
let view = &self.view;
|
||||
let offset: u32 = offset.try_into().map_err(|_| MemoryAccessError::Overflow)?;
|
||||
let len: u32 = buf
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(|_| MemoryAccessError::Overflow)?;
|
||||
let end = offset.checked_add(len).ok_or(MemoryAccessError::Overflow)?;
|
||||
if end > view.length() {
|
||||
Err(MemoryAccessError::HeapOutOfBounds)?;
|
||||
}
|
||||
|
||||
// Zero-initialize the buffer to avoid undefined behavior with
|
||||
// uninitialized data.
|
||||
for elem in buf.iter_mut() {
|
||||
*elem = MaybeUninit::new(0);
|
||||
}
|
||||
let buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len()) };
|
||||
|
||||
view.subarray(offset, end).copy_to(buf);
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
/// Safely writes bytes to the memory at the given offset.
|
||||
///
|
||||
/// If the write exceeds the bounds of the memory then a `MemoryAccessError` is
|
||||
/// returned.
|
||||
///
|
||||
/// This method is guaranteed to be safe (from the host side) in the face of
|
||||
/// concurrent reads/writes.
|
||||
pub fn write(
|
||||
&self,
|
||||
_store: &mut impl AsStoreMut,
|
||||
offset: u64,
|
||||
data: &[u8],
|
||||
) -> Result<(), MemoryAccessError> {
|
||||
let offset: u32 = offset.try_into().map_err(|_| MemoryAccessError::Overflow)?;
|
||||
let len: u32 = data
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(|_| MemoryAccessError::Overflow)?;
|
||||
let view = &self.view;
|
||||
let end = offset.checked_add(len).ok_or(MemoryAccessError::Overflow)?;
|
||||
if end > view.length() {
|
||||
Err(MemoryAccessError::HeapOutOfBounds)?;
|
||||
}
|
||||
view.subarray(offset, end).copy_from(data);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks whether this `Global` can be used with the given context.
|
||||
pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
|
||||
self.handle.store_id() == store.as_store_ref().objects().id()
|
||||
@@ -385,8 +228,8 @@ impl<'a> Exportable<'a> for Memory {
|
||||
/// Underlying buffer for a memory.
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) struct MemoryBuffer<'a> {
|
||||
base: *mut js_sys::Uint8Array,
|
||||
marker: PhantomData<(&'a Memory, &'a StoreObjects)>,
|
||||
pub(crate) base: *mut js_sys::Uint8Array,
|
||||
pub(crate) marker: PhantomData<(&'a Memory, &'a StoreObjects)>,
|
||||
}
|
||||
|
||||
impl<'a> MemoryBuffer<'a> {
|
||||
@@ -396,6 +239,7 @@ impl<'a> MemoryBuffer<'a> {
|
||||
.ok_or(MemoryAccessError::Overflow)?;
|
||||
let view = unsafe { &*(self.base) };
|
||||
if end > view.length().into() {
|
||||
warn!("attempted to read ({} bytes) beyond the bounds of the memory view ({} > {})", buf.len(), end, view.length());
|
||||
return Err(MemoryAccessError::HeapOutOfBounds);
|
||||
}
|
||||
view.subarray(offset as _, end as _)
|
||||
@@ -413,6 +257,7 @@ impl<'a> MemoryBuffer<'a> {
|
||||
.ok_or(MemoryAccessError::Overflow)?;
|
||||
let view = unsafe { &*(self.base) };
|
||||
if end > view.length().into() {
|
||||
warn!("attempted to read ({} bytes) beyond the bounds of the memory view ({} > {})", buf.len(), end, view.length());
|
||||
return Err(MemoryAccessError::HeapOutOfBounds);
|
||||
}
|
||||
let buf_ptr = buf.as_mut_ptr() as *mut u8;
|
||||
@@ -428,6 +273,7 @@ impl<'a> MemoryBuffer<'a> {
|
||||
.ok_or(MemoryAccessError::Overflow)?;
|
||||
let view = unsafe { &mut *(self.base) };
|
||||
if end > view.length().into() {
|
||||
warn!("attempted to write ({} bytes) beyond the bounds of the memory view ({} > {})", data.len(), end, view.length());
|
||||
return Err(MemoryAccessError::HeapOutOfBounds);
|
||||
}
|
||||
view.subarray(offset as _, end as _).copy_from(data);
|
||||
|
||||
186
lib/api/src/js/externals/memory_view.rs
vendored
Normal file
186
lib/api/src/js/externals/memory_view.rs
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
use crate::js::store::AsStoreRef;
|
||||
use crate::js::MemoryAccessError;
|
||||
use std::convert::TryInto;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::slice;
|
||||
use tracing::warn;
|
||||
|
||||
use wasmer_types::{Bytes, Pages};
|
||||
|
||||
use super::Memory;
|
||||
use super::memory::MemoryBuffer;
|
||||
|
||||
/// A WebAssembly `memory` view.
|
||||
///
|
||||
/// A memory view is used to read and write to the linear memory.
|
||||
///
|
||||
/// After a memory is grown a view must not be used anymore. Views are
|
||||
/// created using the Memory.grow() method.
|
||||
#[derive(Debug)]
|
||||
pub struct MemoryView<'a> {
|
||||
view: js_sys::Uint8Array,
|
||||
size: u64,
|
||||
marker: PhantomData<&'a Memory>,
|
||||
}
|
||||
|
||||
impl<'a> MemoryView<'a>
|
||||
{
|
||||
pub(crate) fn new(memory: &Memory, store: &impl AsStoreRef) -> Self {
|
||||
let buffer = memory
|
||||
.handle
|
||||
.get(store.as_store_ref().objects())
|
||||
.memory
|
||||
.buffer();
|
||||
|
||||
let size = js_sys::Reflect::get(
|
||||
&buffer,
|
||||
&"byteLength".into(),
|
||||
)
|
||||
.unwrap()
|
||||
.as_f64()
|
||||
.unwrap() as u64;
|
||||
|
||||
let view = js_sys::Uint8Array::new(
|
||||
&buffer,
|
||||
);
|
||||
|
||||
Self {
|
||||
view,
|
||||
size,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the pointer to the raw bytes of the `Memory`.
|
||||
#[doc(hidden)]
|
||||
pub fn data_ptr(&self) -> *mut u8 {
|
||||
unimplemented!("direct data pointer access is not possible in JavaScript");
|
||||
}
|
||||
|
||||
/// Returns the size (in bytes) of the `Memory`.
|
||||
pub fn data_size(&self) -> u64 {
|
||||
self.size
|
||||
}
|
||||
|
||||
/// Returns the size (in [`Pages`]) of the `Memory`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
|
||||
///
|
||||
/// assert_eq!(m.size(), Pages(1));
|
||||
/// ```
|
||||
pub fn size(&self) -> Pages {
|
||||
Bytes(self.size as usize).try_into().unwrap()
|
||||
}
|
||||
|
||||
/// Used by tests
|
||||
#[doc(hidden)]
|
||||
pub fn uint8view(&self) -> js_sys::Uint8Array {
|
||||
self.view.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn buffer(&self) -> MemoryBuffer<'a> {
|
||||
MemoryBuffer {
|
||||
base: &self.view as *const _ as *mut _,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Safely reads bytes from the memory at the given offset.
|
||||
///
|
||||
/// The full buffer will be filled, otherwise a `MemoryAccessError` is returned
|
||||
/// to indicate an out-of-bounds access.
|
||||
///
|
||||
/// This method is guaranteed to be safe (from the host side) in the face of
|
||||
/// concurrent writes.
|
||||
pub fn read(
|
||||
&self,
|
||||
offset: u64,
|
||||
data: &mut [u8],
|
||||
) -> Result<(), MemoryAccessError> {
|
||||
let view = &self.view;
|
||||
let offset: u32 = offset.try_into().map_err(|_| MemoryAccessError::Overflow)?;
|
||||
let len: u32 = data
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(|_| MemoryAccessError::Overflow)?;
|
||||
let end = offset.checked_add(len).ok_or(MemoryAccessError::Overflow)?;
|
||||
if end > view.length() {
|
||||
warn!("attempted to read ({} bytes) beyond the bounds of the memory view ({} > {})", len, end, view.length());
|
||||
Err(MemoryAccessError::HeapOutOfBounds)?;
|
||||
}
|
||||
view.subarray(offset, end).copy_to(data);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Safely reads bytes from the memory at the given offset.
|
||||
///
|
||||
/// This method is similar to `read` but allows reading into an
|
||||
/// uninitialized buffer. An initialized view of the buffer is returned.
|
||||
///
|
||||
/// The full buffer will be filled, otherwise a `MemoryAccessError` is returned
|
||||
/// to indicate an out-of-bounds access.
|
||||
///
|
||||
/// This method is guaranteed to be safe (from the host side) in the face of
|
||||
/// concurrent writes.
|
||||
pub fn read_uninit(
|
||||
&self,
|
||||
offset: u64,
|
||||
buf: &'a mut [MaybeUninit<u8>],
|
||||
) -> Result<&'a mut [u8], MemoryAccessError> {
|
||||
let view = &self.view;
|
||||
let offset: u32 = offset.try_into().map_err(|_| MemoryAccessError::Overflow)?;
|
||||
let len: u32 = buf
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(|_| MemoryAccessError::Overflow)?;
|
||||
let end = offset.checked_add(len).ok_or(MemoryAccessError::Overflow)?;
|
||||
if end > view.length() {
|
||||
warn!("attempted to read ({} bytes) beyond the bounds of the memory view ({} > {})", len, end, view.length());
|
||||
Err(MemoryAccessError::HeapOutOfBounds)?;
|
||||
}
|
||||
|
||||
// Zero-initialize the buffer to avoid undefined behavior with
|
||||
// uninitialized data.
|
||||
for elem in buf.iter_mut() {
|
||||
*elem = MaybeUninit::new(0);
|
||||
}
|
||||
let buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len()) };
|
||||
|
||||
view.subarray(offset, end).copy_to(buf);
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
/// Safely writes bytes to the memory at the given offset.
|
||||
///
|
||||
/// If the write exceeds the bounds of the memory then a `MemoryAccessError` is
|
||||
/// returned.
|
||||
///
|
||||
/// This method is guaranteed to be safe (from the host side) in the face of
|
||||
/// concurrent reads/writes.
|
||||
pub fn write(
|
||||
&self,
|
||||
offset: u64,
|
||||
data: &[u8],
|
||||
) -> Result<(), MemoryAccessError> {
|
||||
let offset: u32 = offset.try_into().map_err(|_| MemoryAccessError::Overflow)?;
|
||||
let len: u32 = data
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(|_| MemoryAccessError::Overflow)?;
|
||||
let view = &self.view;
|
||||
let end = offset.checked_add(len).ok_or(MemoryAccessError::Overflow)?;
|
||||
if end > view.length() {
|
||||
warn!("attempted to write ({} bytes) beyond the bounds of the memory view ({} > {})", len, end, view.length());
|
||||
Err(MemoryAccessError::HeapOutOfBounds)?;
|
||||
}
|
||||
view.subarray(offset, end).copy_from(data);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
2
lib/api/src/js/externals/mod.rs
vendored
2
lib/api/src/js/externals/mod.rs
vendored
@@ -1,11 +1,13 @@
|
||||
pub(crate) mod function;
|
||||
mod global;
|
||||
pub(crate) mod memory;
|
||||
pub(crate) mod memory_view;
|
||||
mod table;
|
||||
|
||||
pub use self::function::{FromToNativeWasmType, Function, HostFunction, WasmTypeList};
|
||||
pub use self::global::Global;
|
||||
pub use self::memory::{Memory, MemoryError};
|
||||
pub use self::memory_view::MemoryView;
|
||||
pub use self::table::Table;
|
||||
|
||||
use crate::js::export::Export;
|
||||
|
||||
2
lib/api/src/js/externals/table.rs
vendored
2
lib/api/src/js/externals/table.rs
vendored
@@ -128,7 +128,7 @@ impl Table {
|
||||
/// Returns an error if the `delta` is out of bounds for the table.
|
||||
pub fn grow(
|
||||
&self,
|
||||
store: &mut AsStoreMut,
|
||||
_store: &mut impl AsStoreMut,
|
||||
_delta: u32,
|
||||
_init: Value,
|
||||
) -> Result<u32, RuntimeError> {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use crate::js::externals::memory::MemoryBuffer;
|
||||
use crate::js::store::AsStoreRef;
|
||||
use crate::js::RuntimeError;
|
||||
use crate::js::{Memory, Memory32, Memory64, WasmPtr};
|
||||
use crate::js::{MemoryView, Memory32, Memory64, WasmPtr};
|
||||
use std::{
|
||||
convert::TryInto,
|
||||
fmt,
|
||||
@@ -61,9 +60,9 @@ pub struct WasmRef<'a, T: ValueType> {
|
||||
impl<'a, T: ValueType> WasmRef<'a, T> {
|
||||
/// Creates a new `WasmRef` at the given offset in a memory.
|
||||
#[inline]
|
||||
pub fn new(store: &'a impl AsStoreRef, memory: &'a Memory, offset: u64) -> Self {
|
||||
pub fn new(view: &'a MemoryView, offset: u64) -> Self {
|
||||
Self {
|
||||
buffer: memory.buffer(store),
|
||||
buffer: view.buffer(),
|
||||
offset,
|
||||
marker: PhantomData,
|
||||
}
|
||||
@@ -160,8 +159,7 @@ impl<'a, T: ValueType> WasmSlice<'a, T> {
|
||||
/// Returns a `MemoryAccessError` if the slice length overflows.
|
||||
#[inline]
|
||||
pub fn new(
|
||||
store: &'a impl AsStoreRef,
|
||||
memory: &'a Memory,
|
||||
memory: &'a MemoryView,
|
||||
offset: u64,
|
||||
len: u64,
|
||||
) -> Result<Self, MemoryAccessError> {
|
||||
@@ -172,7 +170,7 @@ impl<'a, T: ValueType> WasmSlice<'a, T> {
|
||||
.checked_add(total_len)
|
||||
.ok_or(MemoryAccessError::Overflow)?;
|
||||
Ok(Self {
|
||||
buffer: memory.buffer(store),
|
||||
buffer: memory.buffer(),
|
||||
offset,
|
||||
len,
|
||||
marker: PhantomData,
|
||||
|
||||
@@ -48,7 +48,7 @@ pub use crate::js::error::{DeserializeError, InstantiationError, SerializeError}
|
||||
pub use crate::js::export::Export;
|
||||
pub use crate::js::exports::{ExportError, Exportable, Exports, ExportsIterator};
|
||||
pub use crate::js::externals::{
|
||||
Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryError, Table,
|
||||
Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryView, MemoryError, Table,
|
||||
WasmTypeList,
|
||||
};
|
||||
pub use crate::js::function_env::{FunctionEnv, FunctionEnvMut};
|
||||
|
||||
@@ -5,7 +5,6 @@ use crate::js::error::{CompileError, InstantiationError};
|
||||
use crate::js::error::{DeserializeError, SerializeError};
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::imports::Imports;
|
||||
use crate::js::store::Store;
|
||||
use crate::js::store::{AsStoreMut, StoreHandle};
|
||||
use crate::js::types::{AsJs, ExportType, ImportType};
|
||||
use crate::js::RuntimeError;
|
||||
|
||||
@@ -39,7 +39,7 @@ where
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn new<T>(
|
||||
store: &mut impl AsStoreMut,
|
||||
env: &FunctionEnv<T>,
|
||||
_env: &FunctionEnv<T>,
|
||||
vm_function: VMFunction,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use crate::js::store::AsStoreRef;
|
||||
use crate::js::NativeWasmTypeInto;
|
||||
use crate::js::{externals::Memory, FromToNativeWasmType};
|
||||
use crate::js::{externals::MemoryView, FromToNativeWasmType};
|
||||
use crate::js::{MemoryAccessError, WasmRef, WasmSlice};
|
||||
use std::convert::TryFrom;
|
||||
use std::{fmt, marker::PhantomData, mem};
|
||||
@@ -138,25 +137,24 @@ impl<T: ValueType, M: MemorySize> WasmPtr<T, M> {
|
||||
/// Creates a `WasmRef` from this `WasmPtr` which allows reading and
|
||||
/// mutating of the value being pointed to.
|
||||
#[inline]
|
||||
pub fn deref<'a>(self, store: &'a impl AsStoreRef, memory: &'a Memory) -> WasmRef<'a, T> {
|
||||
WasmRef::new(store, memory, self.offset.into())
|
||||
pub fn deref<'a>(self, view: &'a MemoryView) -> WasmRef<'a, T> {
|
||||
WasmRef::new(view, self.offset.into())
|
||||
}
|
||||
|
||||
/// Reads the address pointed to by this `WasmPtr` in a memory.
|
||||
#[inline]
|
||||
pub fn read(self, store: &impl AsStoreRef, memory: &Memory) -> Result<T, MemoryAccessError> {
|
||||
self.deref(store, memory).read()
|
||||
pub fn read(self, view: &MemoryView) -> Result<T, MemoryAccessError> {
|
||||
self.deref(view).read()
|
||||
}
|
||||
|
||||
/// Writes to the address pointed to by this `WasmPtr` in a memory.
|
||||
#[inline]
|
||||
pub fn write(
|
||||
self,
|
||||
store: &impl AsStoreRef,
|
||||
memory: &Memory,
|
||||
view: &MemoryView,
|
||||
val: T,
|
||||
) -> Result<(), MemoryAccessError> {
|
||||
self.deref(store, memory).write(val)
|
||||
self.deref(view).write(val)
|
||||
}
|
||||
|
||||
/// Creates a `WasmSlice` starting at this `WasmPtr` which allows reading
|
||||
@@ -167,11 +165,10 @@ impl<T: ValueType, M: MemorySize> WasmPtr<T, M> {
|
||||
#[inline]
|
||||
pub fn slice<'a>(
|
||||
self,
|
||||
store: &'a impl AsStoreRef,
|
||||
memory: &'a Memory,
|
||||
view: &'a MemoryView,
|
||||
len: M::Offset,
|
||||
) -> Result<WasmSlice<'a, T>, MemoryAccessError> {
|
||||
WasmSlice::new(store, memory, self.offset.into(), len.into())
|
||||
WasmSlice::new(view, self.offset.into(), len.into())
|
||||
}
|
||||
|
||||
/// Reads a sequence of values from this `WasmPtr` until a value that
|
||||
@@ -181,14 +178,13 @@ impl<T: ValueType, M: MemorySize> WasmPtr<T, M> {
|
||||
#[inline]
|
||||
pub fn read_until<'a>(
|
||||
self,
|
||||
store: &'a impl AsStoreRef,
|
||||
memory: &'a Memory,
|
||||
view: &'a MemoryView,
|
||||
mut end: impl FnMut(&T) -> bool,
|
||||
) -> Result<Vec<T>, MemoryAccessError> {
|
||||
let mut vec = Vec::new();
|
||||
for i in 0u64.. {
|
||||
let i = M::Offset::try_from(i).map_err(|_| MemoryAccessError::Overflow)?;
|
||||
let val = self.add_offset(i)?.deref(store, memory).read()?;
|
||||
let val = self.add_offset(i)?.deref(view).read()?;
|
||||
if end(&val) {
|
||||
break;
|
||||
}
|
||||
@@ -206,11 +202,10 @@ impl<M: MemorySize> WasmPtr<u8, M> {
|
||||
#[inline]
|
||||
pub fn read_utf8_string<'a>(
|
||||
self,
|
||||
store: &'a impl AsStoreRef,
|
||||
memory: &'a Memory,
|
||||
view: &'a MemoryView,
|
||||
len: M::Offset,
|
||||
) -> Result<String, MemoryAccessError> {
|
||||
let vec = self.slice(store, memory, len)?.read_to_vec()?;
|
||||
let vec = self.slice(view, len)?.read_to_vec()?;
|
||||
Ok(String::from_utf8(vec)?)
|
||||
}
|
||||
|
||||
@@ -221,10 +216,9 @@ impl<M: MemorySize> WasmPtr<u8, M> {
|
||||
#[inline]
|
||||
pub fn read_utf8_string_with_nul<'a>(
|
||||
self,
|
||||
store: &'a impl AsStoreRef,
|
||||
memory: &'a Memory,
|
||||
view: &'a MemoryView,
|
||||
) -> Result<String, MemoryAccessError> {
|
||||
let vec = self.read_until(store, memory, |&byte| byte == 0)?;
|
||||
let vec = self.read_until(view, |&byte| byte == 0)?;
|
||||
Ok(String::from_utf8(vec)?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +182,6 @@ impl<T: AsStoreMut> AsStoreMut for &'_ mut T {
|
||||
|
||||
pub use objects::*;
|
||||
|
||||
use crate::js::FunctionEnv;
|
||||
mod objects {
|
||||
use crate::js::{
|
||||
export::{VMFunction, VMGlobal, VMMemory, VMTable},
|
||||
@@ -433,6 +432,7 @@ mod objects {
|
||||
/// Data used by the generated code is generally located inline within the
|
||||
/// `VMContext` for items defined in an instance. Host-defined objects are
|
||||
/// allocated separately and owned directly by the context.
|
||||
#[allow(dead_code)]
|
||||
pub enum MaybeInstanceOwned<T> {
|
||||
/// The data is owned here.
|
||||
Host(Box<UnsafeCell<T>>),
|
||||
@@ -443,6 +443,7 @@ mod objects {
|
||||
|
||||
impl<T> MaybeInstanceOwned<T> {
|
||||
/// Returns underlying pointer to the VM data.
|
||||
#[allow(dead_code)]
|
||||
pub fn as_ptr(&self) -> NonNull<T> {
|
||||
match self {
|
||||
MaybeInstanceOwned::Host(p) => unsafe { NonNull::new_unchecked(p.get()) },
|
||||
|
||||
Reference in New Issue
Block a user