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