mirror of
https://github.com/fluencelabs/wasmer
synced 2025-03-16 08:10:49 +00:00
Fix memory api to be sound
This commit is contained in:
parent
a58f3318f0
commit
9b491ec95d
@ -8,13 +8,15 @@ fn main() -> Result<()> {
|
||||
let wasm_binary = wat2wasm(IMPORT_MODULE.as_bytes()).expect("WAST not valid or malformed");
|
||||
let inner_module = wasmer_runtime_core::compile_with(&wasm_binary, &CraneliftCompiler::new())?;
|
||||
|
||||
let mut memory = Memory::new(MemoryDesc {
|
||||
let memory = Memory::new(MemoryDesc {
|
||||
min: 1,
|
||||
max: Some(1),
|
||||
shared: false,
|
||||
}).unwrap();
|
||||
|
||||
memory.as_slice_mut()[0] = 42;
|
||||
memory.direct_access_mut(|slice: &mut [u32]| {
|
||||
slice[0] = 42;
|
||||
});
|
||||
|
||||
let import_object = imports! {
|
||||
"env" => {
|
||||
|
@ -104,11 +104,8 @@ impl LocalBacking {
|
||||
let data_top = init_base + init.data.len();
|
||||
assert!(memory_desc.min as usize * WASM_PAGE_SIZE >= data_top);
|
||||
|
||||
let mem: &mut Memory = &mut memories[local_memory_index];
|
||||
let mem_init_view =
|
||||
&mut mem.as_slice_mut()[init_base..init_base + init.data.len()];
|
||||
|
||||
mem_init_view.copy_from_slice(&init.data);
|
||||
let mem = &memories[local_memory_index];
|
||||
mem.set(init_base as u32, &init.data).unwrap();
|
||||
}
|
||||
LocalOrImport::Import(imported_memory_index) => {
|
||||
// Write the initialization data to the memory that
|
||||
|
91
lib/runtime-core/src/global.rs
Normal file
91
lib/runtime-core/src/global.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use crate::{
|
||||
types::{GlobalDesc, Type, Value},
|
||||
vm,
|
||||
};
|
||||
use std::{cell::UnsafeCell, rc::Rc};
|
||||
|
||||
pub struct Global {
|
||||
desc: GlobalDesc,
|
||||
storage: Rc<UnsafeCell<vm::LocalGlobal>>,
|
||||
}
|
||||
|
||||
impl Global {
|
||||
pub fn new(value: Value) -> Self {
|
||||
Self::_new(value, false)
|
||||
}
|
||||
|
||||
pub fn new_mutable(value: Value) -> Self {
|
||||
Self::_new(value, true)
|
||||
}
|
||||
|
||||
fn _new(value: Value, mutable: bool) -> Self {
|
||||
let desc = GlobalDesc {
|
||||
mutable,
|
||||
ty: value.ty(),
|
||||
};
|
||||
|
||||
let local_global = vm::LocalGlobal {
|
||||
data: match value {
|
||||
Value::I32(x) => x as u64,
|
||||
Value::I64(x) => x as u64,
|
||||
Value::F32(x) => x.to_bits() as u64,
|
||||
Value::F64(x) => x.to_bits(),
|
||||
},
|
||||
};
|
||||
|
||||
Self {
|
||||
desc,
|
||||
storage: Rc::new(UnsafeCell::new(local_global))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn description(&self) -> GlobalDesc {
|
||||
self.desc
|
||||
}
|
||||
|
||||
pub fn set(&mut self, value: Value) {
|
||||
if self.desc.mutable {
|
||||
if self.desc.ty == value.ty() {
|
||||
let local_global = vm::LocalGlobal {
|
||||
data: match value {
|
||||
Value::I32(x) => x as u64,
|
||||
Value::I64(x) => x as u64,
|
||||
Value::F32(x) => x.to_bits() as u64,
|
||||
Value::F64(x) => x.to_bits(),
|
||||
},
|
||||
};
|
||||
unsafe {
|
||||
(*self.storage.get()) = local_global;
|
||||
}
|
||||
} else {
|
||||
panic!("Wrong type for setting this global")
|
||||
}
|
||||
} else {
|
||||
panic!("Cannot modify global immutable by default")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self) -> Value {
|
||||
let data = unsafe { (*self.storage.get()).data };
|
||||
|
||||
match self.desc.ty {
|
||||
Type::I32 => Value::I32(data as i32),
|
||||
Type::I64 => Value::I64(data as i64),
|
||||
Type::F32 => Value::F32(f32::from_bits(data as u32)),
|
||||
Type::F64 => Value::F64(f64::from_bits(data)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn vm_local_global(&mut self) -> *mut vm::LocalGlobal {
|
||||
&mut *unsafe { &mut *self.storage.get() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Global {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
desc: self.desc,
|
||||
storage: Rc::clone(&self.storage),
|
||||
}
|
||||
}
|
||||
}
|
@ -24,11 +24,11 @@ impl IsExport for Export {
|
||||
///
|
||||
/// # Usage:
|
||||
/// ```
|
||||
/// # use wasmer_runtime_core::imports;
|
||||
/// # use wasmer_runtime_core::{imports, func};
|
||||
/// # use wasmer_runtime_core::vm::Ctx;
|
||||
/// let import_object = imports! {
|
||||
/// "env" => {
|
||||
/// "foo" => foo<[i32] -> [i32]>,
|
||||
/// "foo" => func!(foo, [i32] -> [i32]),
|
||||
/// },
|
||||
/// };
|
||||
///
|
||||
|
@ -64,11 +64,11 @@ macro_rules! __export_func_convert_type {
|
||||
///
|
||||
/// # Usage:
|
||||
/// ```
|
||||
/// # use wasmer_runtime_core::imports;
|
||||
/// # use wasmer_runtime_core::{imports, func};
|
||||
/// # use wasmer_runtime_core::vm::Ctx;
|
||||
/// let import_object = imports! {
|
||||
/// "env" => {
|
||||
/// "foo" => foo<[i32] -> [i32]>,
|
||||
/// "foo" => func!(foo, [i32] -> [i32]),
|
||||
/// },
|
||||
/// };
|
||||
///
|
||||
|
@ -3,10 +3,10 @@ use crate::{
|
||||
import::IsExport,
|
||||
memory::dynamic::DYNAMIC_GUARD_SIZE,
|
||||
memory::static_::{SAFE_STATIC_GUARD_SIZE, SAFE_STATIC_HEAP_SIZE},
|
||||
types::MemoryDesc,
|
||||
types::{MemoryDesc, ValueType},
|
||||
vm,
|
||||
};
|
||||
use std::{cell::UnsafeCell, fmt, ptr, rc::Rc};
|
||||
use std::{cell::RefCell, fmt, mem, ptr, slice, rc::Rc};
|
||||
|
||||
pub use self::dynamic::DynamicMemory;
|
||||
pub use self::static_::{SharedStaticMemory, StaticMemory};
|
||||
@ -19,7 +19,7 @@ pub const WASM_MAX_PAGES: usize = 65_536;
|
||||
|
||||
pub struct Memory {
|
||||
desc: MemoryDesc,
|
||||
storage: Rc<UnsafeCell<(MemoryStorage, Box<vm::LocalMemory>)>>,
|
||||
storage: Rc<RefCell<(MemoryStorage, Box<vm::LocalMemory>)>>,
|
||||
}
|
||||
|
||||
impl Memory {
|
||||
@ -42,7 +42,7 @@ impl Memory {
|
||||
|
||||
Some(Memory {
|
||||
desc,
|
||||
storage: Rc::new(UnsafeCell::new((memory_storage, vm_local_memory))),
|
||||
storage: Rc::new(RefCell::new((memory_storage, vm_local_memory))),
|
||||
})
|
||||
}
|
||||
|
||||
@ -51,40 +51,112 @@ impl Memory {
|
||||
}
|
||||
|
||||
pub fn grow(&mut self, delta: u32) -> Option<u32> {
|
||||
match unsafe { &mut *self.storage.get() } {
|
||||
(MemoryStorage::Dynamic(dynamic_memory), local) => dynamic_memory.grow(delta, local),
|
||||
(MemoryStorage::Static(static_memory), local) => static_memory.grow(delta, local),
|
||||
match &mut *self.storage.borrow_mut() {
|
||||
(MemoryStorage::Dynamic(ref mut dynamic_memory), ref mut local) => dynamic_memory.grow(delta, local),
|
||||
(MemoryStorage::Static(ref mut static_memory), ref mut local) => static_memory.grow(delta, local),
|
||||
(MemoryStorage::SharedStatic(_), _) => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// This returns the number of pages in the memory.
|
||||
pub fn current_pages(&self) -> u32 {
|
||||
match unsafe { &*self.storage.get() } {
|
||||
(MemoryStorage::Dynamic(dynamic_memory), _) => dynamic_memory.current(),
|
||||
(MemoryStorage::Static(static_memory), _) => static_memory.current(),
|
||||
match &*self.storage.borrow() {
|
||||
(MemoryStorage::Dynamic(ref dynamic_memory), _) => dynamic_memory.current(),
|
||||
(MemoryStorage::Static(ref static_memory), _) => static_memory.current(),
|
||||
(MemoryStorage::SharedStatic(_), _) => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
match unsafe { &*self.storage.get() } {
|
||||
(MemoryStorage::Dynamic(dynamic_memory), _) => dynamic_memory.as_slice(),
|
||||
(MemoryStorage::Static(static_memory), _) => static_memory.as_slice(),
|
||||
(MemoryStorage::SharedStatic(_), _) => panic!("cannot slice a shared memory"),
|
||||
pub fn get<T: ValueType>(&self, offset: u32, count: usize) -> Result<Vec<T>, ()> {
|
||||
let offset = offset as usize;
|
||||
let borrow_ref = self.storage.borrow();
|
||||
let memory_storage = &borrow_ref.0;
|
||||
|
||||
let mem_slice = match memory_storage {
|
||||
MemoryStorage::Dynamic(ref dynamic_memory) => dynamic_memory.as_slice(),
|
||||
MemoryStorage::Static(ref static_memory) => static_memory.as_slice(),
|
||||
MemoryStorage::SharedStatic(_) => panic!("cannot slice a shared memory"),
|
||||
};
|
||||
|
||||
let bytes_size = count * mem::size_of::<T>();
|
||||
|
||||
if offset + bytes_size <= mem_slice.len() {
|
||||
let buffer = &mem_slice[offset .. offset + bytes_size];
|
||||
let value_type_buffer = unsafe {
|
||||
slice::from_raw_parts(buffer.as_ptr() as *const T, buffer.len() / mem::size_of::<T>())
|
||||
};
|
||||
Ok(value_type_buffer.to_vec())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_slice_mut(&mut self) -> &mut [u8] {
|
||||
match unsafe { &mut *self.storage.get() } {
|
||||
(MemoryStorage::Dynamic(dynamic_memory), _) => dynamic_memory.as_slice_mut(),
|
||||
(MemoryStorage::Static(static_memory), _) => static_memory.as_slice_mut(),
|
||||
(MemoryStorage::SharedStatic(_), _) => panic!("cannot slice a shared memory"),
|
||||
pub fn set<T: ValueType>(&self, offset: u32, values: &[T]) -> Result<(), ()> {
|
||||
let offset = offset as usize;
|
||||
let mut borrow_ref = self.storage.borrow_mut();
|
||||
let memory_storage = &mut borrow_ref.0;
|
||||
|
||||
let mem_slice = match memory_storage {
|
||||
MemoryStorage::Dynamic(ref mut dynamic_memory) => dynamic_memory.as_slice_mut(),
|
||||
MemoryStorage::Static(ref mut static_memory) => static_memory.as_slice_mut(),
|
||||
MemoryStorage::SharedStatic(_) => panic!("cannot slice a shared memory"),
|
||||
};
|
||||
|
||||
let bytes_size = values.len() * mem::size_of::<T>();
|
||||
|
||||
if offset + bytes_size <= mem_slice.len() {
|
||||
let u8_buffer = unsafe {
|
||||
slice::from_raw_parts(values.as_ptr() as *const u8, bytes_size)
|
||||
};
|
||||
mem_slice[offset .. offset + bytes_size].copy_from_slice(u8_buffer);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn direct_access<T: ValueType, F, R>(&self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&[T]) -> R,
|
||||
{
|
||||
let borrow_ref = self.storage.borrow();
|
||||
let memory_storage = &borrow_ref.0;
|
||||
|
||||
let mem_slice = match memory_storage {
|
||||
MemoryStorage::Dynamic(ref dynamic_memory) => dynamic_memory.as_slice(),
|
||||
MemoryStorage::Static(ref static_memory) => static_memory.as_slice(),
|
||||
MemoryStorage::SharedStatic(_) => panic!("cannot slice a shared memory"),
|
||||
};
|
||||
|
||||
let t_buffer = unsafe {
|
||||
slice::from_raw_parts(mem_slice.as_ptr() as *const T, mem_slice.len() / mem::size_of::<T>())
|
||||
};
|
||||
|
||||
f(t_buffer)
|
||||
}
|
||||
|
||||
pub fn direct_access_mut<T: ValueType, F, R>(&self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut [T]) -> R,
|
||||
{
|
||||
let mut borrow_ref = self.storage.borrow_mut();
|
||||
let memory_storage = &mut borrow_ref.0;
|
||||
|
||||
let mem_slice = match memory_storage {
|
||||
MemoryStorage::Dynamic(ref mut dynamic_memory) => dynamic_memory.as_slice_mut(),
|
||||
MemoryStorage::Static(ref mut static_memory) => static_memory.as_slice_mut(),
|
||||
MemoryStorage::SharedStatic(_) => panic!("cannot slice a shared memory"),
|
||||
};
|
||||
|
||||
let t_buffer = unsafe {
|
||||
slice::from_raw_parts_mut(mem_slice.as_mut_ptr() as *mut T, mem_slice.len() / mem::size_of::<T>())
|
||||
};
|
||||
|
||||
f(t_buffer)
|
||||
}
|
||||
|
||||
pub(crate) fn vm_local_memory(&mut self) -> *mut vm::LocalMemory {
|
||||
&mut *unsafe { &mut *self.storage.get() }.1
|
||||
&mut *self.storage.borrow_mut().1
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::{memory::MemoryType, module::ModuleInner, structures::TypedIndex};
|
||||
use std::mem;
|
||||
|
||||
/// Represents a WebAssembly type.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
@ -64,6 +65,62 @@ impl From<f64> for Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ValueError {
|
||||
BufferTooSmall,
|
||||
}
|
||||
|
||||
pub trait ValueType: Copy + Clone
|
||||
where
|
||||
Self: Sized
|
||||
{
|
||||
fn into_le(self, buffer: &mut [u8]);
|
||||
fn from_le(buffer: &[u8]) -> Result<Self, ValueError>;
|
||||
}
|
||||
|
||||
macro_rules! convert_value_impl {
|
||||
($t:ty) => {
|
||||
impl ValueType for $t {
|
||||
fn into_le(self, buffer: &mut [u8]) {
|
||||
buffer.copy_from_slice(&self.to_le_bytes());
|
||||
}
|
||||
fn from_le(buffer: &[u8]) -> Result<Self, ValueError> {
|
||||
if buffer.len() >= mem::size_of::<Self>() {
|
||||
let mut array = [0u8; mem::size_of::<Self>()];
|
||||
array.copy_from_slice(buffer);
|
||||
Ok(Self::from_le_bytes(array))
|
||||
} else {
|
||||
Err(ValueError::BufferTooSmall)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
( $($t:ty),* ) => {
|
||||
$(
|
||||
convert_value_impl!($t);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
convert_value_impl!(u8, i8, u16, i16, u32, i32, u64, i64);
|
||||
|
||||
impl ValueType for f32 {
|
||||
fn into_le(self, buffer: &mut [u8]) {
|
||||
self.to_bits().into_le(buffer);
|
||||
}
|
||||
fn from_le(buffer: &[u8]) -> Result<Self, ValueError> {
|
||||
Ok(f32::from_bits(<u32 as ValueType>::from_le(buffer)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl ValueType for f64 {
|
||||
fn into_le(self, buffer: &mut [u8]) {
|
||||
self.to_bits().into_le(buffer);
|
||||
}
|
||||
fn from_le(buffer: &[u8]) -> Result<Self, ValueError> {
|
||||
Ok(f64::from_bits(<u64 as ValueType>::from_le(buffer)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ElementType {
|
||||
/// Any wasm function.
|
||||
|
Loading…
x
Reference in New Issue
Block a user