mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-12 16:41:21 +00:00
merge upstream/master into wasmer-private/feature/llvm-backend
This commit is contained in:
@ -12,7 +12,7 @@ use crate::{
|
||||
module::ModuleInfo,
|
||||
sys::Memory,
|
||||
};
|
||||
use std::ptr::NonNull;
|
||||
use std::{any::Any, ptr::NonNull};
|
||||
|
||||
pub mod sys {
|
||||
pub use crate::sys::*;
|
||||
@ -79,7 +79,7 @@ pub trait ProtectedCaller: Send + Sync {
|
||||
}
|
||||
|
||||
pub trait UserTrapper {
|
||||
unsafe fn do_early_trap(&self, msg: String) -> !;
|
||||
unsafe fn do_early_trap(&self, data: Box<dyn Any>) -> !;
|
||||
}
|
||||
|
||||
pub trait FuncResolver: Send + Sync {
|
||||
|
@ -2,8 +2,8 @@ use crate::{
|
||||
module::{Module, ModuleInfo},
|
||||
sys::Memory,
|
||||
};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::{io, mem, slice};
|
||||
use blake2b_simd::blake2bp;
|
||||
use std::{fmt, io, mem, slice};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum InvalidFileType {
|
||||
@ -33,7 +33,7 @@ impl From<io::Error> for Error {
|
||||
///
|
||||
/// [`Cache`]: trait.Cache.html
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct WasmHash([u8; 32]);
|
||||
pub struct WasmHash([u8; 32], [u8; 32]);
|
||||
|
||||
impl WasmHash {
|
||||
/// Hash a wasm module.
|
||||
@ -42,19 +42,31 @@ impl WasmHash {
|
||||
/// This does no verification that the supplied data
|
||||
/// is, in fact, a wasm module.
|
||||
pub fn generate(wasm: &[u8]) -> Self {
|
||||
let mut array = [0u8; 32];
|
||||
array.copy_from_slice(Sha256::digest(wasm).as_slice());
|
||||
WasmHash(array)
|
||||
let mut first_part = [0u8; 32];
|
||||
let mut second_part = [0u8; 32];
|
||||
|
||||
let mut state = blake2bp::State::new();
|
||||
state.update(wasm);
|
||||
|
||||
let hasher = state.finalize();
|
||||
let generic_array = hasher.as_bytes();
|
||||
|
||||
first_part.copy_from_slice(&generic_array[0..32]);
|
||||
second_part.copy_from_slice(&generic_array[32..64]);
|
||||
WasmHash(first_part, second_part)
|
||||
}
|
||||
|
||||
/// Create the hexadecimal representation of the
|
||||
/// stored hash.
|
||||
pub fn encode(self) -> String {
|
||||
hex::encode(self.0)
|
||||
hex::encode(&self.into_array() as &[u8])
|
||||
}
|
||||
|
||||
pub(crate) fn into_array(self) -> [u8; 32] {
|
||||
self.0
|
||||
pub(crate) fn into_array(self) -> [u8; 64] {
|
||||
let mut total = [0u8; 64];
|
||||
total[0..32].copy_from_slice(&self.0);
|
||||
total[32..64].copy_from_slice(&self.1);
|
||||
total
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,8 +201,8 @@ impl Artifact {
|
||||
///
|
||||
/// The `wasmer-runtime` supplies a naive `FileSystemCache` api.
|
||||
pub trait Cache {
|
||||
type LoadError;
|
||||
type StoreError;
|
||||
type LoadError: fmt::Debug;
|
||||
type StoreError: fmt::Debug;
|
||||
|
||||
fn load(&self, key: WasmHash) -> Result<Module, Self::LoadError>;
|
||||
fn store(&mut self, key: WasmHash, module: Module) -> Result<(), Self::StoreError>;
|
||||
|
@ -1,8 +1,9 @@
|
||||
use crate::types::{
|
||||
FuncSig, GlobalDescriptor, MemoryDescriptor, MemoryIndex, TableDescriptor, TableIndex, Type,
|
||||
Value,
|
||||
};
|
||||
use core::borrow::Borrow;
|
||||
use std::sync::Arc;
|
||||
use std::{any::Any, sync::Arc};
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
pub type CompileResult<T> = std::result::Result<T, CompileError>;
|
||||
@ -120,28 +121,11 @@ impl std::error::Error for LinkError {}
|
||||
/// The main way to do this is `Instance.call`.
|
||||
///
|
||||
/// Comparing two `RuntimeError`s always evaluates to false.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum RuntimeError {
|
||||
OutOfBoundsAccess {
|
||||
memory: MemoryIndex,
|
||||
addr: Option<u32>,
|
||||
},
|
||||
TableOutOfBounds {
|
||||
table: TableIndex,
|
||||
},
|
||||
IndirectCallSignature {
|
||||
table: TableIndex,
|
||||
},
|
||||
IndirectCallToNull {
|
||||
table: TableIndex,
|
||||
},
|
||||
IllegalArithmeticOperation,
|
||||
User {
|
||||
msg: String,
|
||||
},
|
||||
Unknown {
|
||||
msg: String,
|
||||
},
|
||||
Trap { msg: Box<str> },
|
||||
Exception { data: Box<[Value]> },
|
||||
Panic { data: Box<dyn Any> },
|
||||
}
|
||||
|
||||
impl PartialEq for RuntimeError {
|
||||
@ -153,30 +137,13 @@ impl PartialEq for RuntimeError {
|
||||
impl std::fmt::Display for RuntimeError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
RuntimeError::IndirectCallSignature { table } => write!(
|
||||
f,
|
||||
"Indirect call signature error with Table Index \"{:?}\"",
|
||||
table
|
||||
),
|
||||
RuntimeError::IndirectCallToNull { table } => {
|
||||
write!(f, "Indirect call to null with table index \"{:?}\"", table)
|
||||
RuntimeError::Trap { ref msg } => {
|
||||
write!(f, "WebAssembly trap occured during runtime: {}", msg)
|
||||
}
|
||||
RuntimeError::IllegalArithmeticOperation => write!(f, "Illegal arithmetic operation"),
|
||||
RuntimeError::OutOfBoundsAccess { memory, addr } => match addr {
|
||||
Some(addr) => write!(
|
||||
f,
|
||||
"Out-of-bounds access with memory index {:?} and address {}",
|
||||
memory, addr
|
||||
),
|
||||
None => write!(f, "Out-of-bounds access with memory index {:?}", memory),
|
||||
},
|
||||
RuntimeError::TableOutOfBounds { table } => {
|
||||
write!(f, "Table out of bounds with table index \"{:?}\"", table)
|
||||
RuntimeError::Exception { ref data } => {
|
||||
write!(f, "Uncaught WebAssembly exception: {:?}", data)
|
||||
}
|
||||
RuntimeError::Unknown { msg } => {
|
||||
write!(f, "Unknown runtime error with message: \"{}\"", msg)
|
||||
}
|
||||
RuntimeError::User { msg } => write!(f, "User runtime error with message: \"{}\"", msg),
|
||||
RuntimeError::Panic { data: _ } => write!(f, "User-defined \"panic\""),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -232,7 +199,7 @@ impl std::error::Error for ResolveError {}
|
||||
/// be the `CallError::Runtime(RuntimeError)` variant.
|
||||
///
|
||||
/// Comparing two `CallError`s always evaluates to false.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum CallError {
|
||||
Resolve(ResolveError),
|
||||
Runtime(RuntimeError),
|
||||
@ -291,7 +258,7 @@ impl std::error::Error for CreationError {}
|
||||
/// of a webassembly module.
|
||||
///
|
||||
/// Comparing two `Error`s always evaluates to false.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
CompileError(CompileError),
|
||||
LinkError(Vec<LinkError>),
|
||||
@ -357,8 +324,127 @@ impl From<ResolveError> for CallError {
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
match self {
|
||||
Error::CompileError(err) => write!(f, "compile error: {}", err),
|
||||
Error::LinkError(errs) => {
|
||||
if errs.len() == 1 {
|
||||
write!(f, "link error: {}", errs[0])
|
||||
} else {
|
||||
write!(f, "{} link errors:", errs.len())?;
|
||||
for (i, err) in errs.iter().enumerate() {
|
||||
write!(f, " ({} of {}) {}", i + 1, errs.len(), err)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Error::RuntimeError(err) => write!(f, "runtime error: {}", err),
|
||||
Error::ResolveError(err) => write!(f, "resolve error: {}", err),
|
||||
Error::CallError(err) => write!(f, "call error: {}", err),
|
||||
Error::CreationError(err) => write!(f, "creation error: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum GrowError {
|
||||
MemoryGrowError,
|
||||
TableGrowError,
|
||||
ExceededMaxPages(PageError),
|
||||
ExceededMaxPagesForMemory(usize, usize),
|
||||
CouldNotProtectMemory(MemoryProtectionError),
|
||||
CouldNotCreateMemory(MemoryCreationError),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for GrowError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
GrowError::MemoryGrowError => write!(f, "Unable to grow memory"),
|
||||
GrowError::TableGrowError => write!(f, "Unable to grow table"),
|
||||
GrowError::ExceededMaxPages(e) => write!(f, "Grow Error: {}", e),
|
||||
GrowError::ExceededMaxPagesForMemory(left, added) => write!(f, "Failed to add pages because would exceed maximum number of pages for the memory. Left: {}, Added: {}", left, added),
|
||||
GrowError::CouldNotCreateMemory(e) => write!(f, "Grow Error: {}", e),
|
||||
GrowError::CouldNotProtectMemory(e) => write!(f, "Grow Error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for GrowError {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PageError {
|
||||
// left, right, added
|
||||
ExceededMaxPages(usize, usize, usize),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for PageError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
PageError::ExceededMaxPages(left, right, added) => write!(f, "Failed to add pages because would exceed maximum number of pages. Left: {}, Right: {}, Pages added: {}", left, right, added),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::error::Error for PageError {}
|
||||
|
||||
impl Into<GrowError> for PageError {
|
||||
fn into(self) -> GrowError {
|
||||
GrowError::ExceededMaxPages(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MemoryCreationError {
|
||||
VirtualMemoryAllocationFailed(usize, String),
|
||||
CouldNotCreateMemoryFromFile(std::io::Error),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for MemoryCreationError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
MemoryCreationError::VirtualMemoryAllocationFailed(size, msg) => write!(
|
||||
f,
|
||||
"Allocation virtual memory with size {} failed. \nErrno message: {}",
|
||||
size, msg
|
||||
),
|
||||
MemoryCreationError::CouldNotCreateMemoryFromFile(e) => write!(f, "IO Error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::error::Error for MemoryCreationError {}
|
||||
|
||||
impl Into<GrowError> for MemoryCreationError {
|
||||
fn into(self) -> GrowError {
|
||||
GrowError::CouldNotCreateMemory(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for MemoryCreationError {
|
||||
fn from(io_error: std::io::Error) -> Self {
|
||||
MemoryCreationError::CouldNotCreateMemoryFromFile(io_error)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MemoryProtectionError {
|
||||
ProtectionFailed(usize, usize, String),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for MemoryProtectionError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
MemoryProtectionError::ProtectionFailed(start, size, msg) => write!(
|
||||
f,
|
||||
"Allocation virtual memory starting at {} with size {} failed. \nErrno message: {}",
|
||||
start, size, msg
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::error::Error for MemoryProtectionError {}
|
||||
|
||||
impl Into<GrowError> for MemoryProtectionError {
|
||||
fn into(self) -> GrowError {
|
||||
GrowError::CouldNotProtectMemory(self)
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::error::GrowError;
|
||||
use crate::{
|
||||
error::CreationError,
|
||||
sys,
|
||||
@ -14,9 +15,9 @@ pub const DYNAMIC_GUARD_SIZE: usize = 4096;
|
||||
/// when first created. Over time, as it grows, it may reallocate to
|
||||
/// a different location and size.
|
||||
///
|
||||
/// Dynamic memories are signifigantly faster to create than static
|
||||
/// Dynamic memories are significantly faster to create than static
|
||||
/// memories and use much less virtual memory, however, they require
|
||||
/// the webassembly module to bounds-check memory accesses.
|
||||
/// the WebAssembly module to bounds-check memory accesses.
|
||||
///
|
||||
/// While, a dynamic memory could use a vector of some sort as its
|
||||
/// backing memory, we use mmap (or the platform-equivalent) to allow
|
||||
@ -65,26 +66,29 @@ impl DynamicMemory {
|
||||
self.current
|
||||
}
|
||||
|
||||
pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Option<Pages> {
|
||||
pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Result<Pages, GrowError> {
|
||||
if delta == Pages(0) {
|
||||
return Some(self.current);
|
||||
return Ok(self.current);
|
||||
}
|
||||
|
||||
let new_pages = self.current.checked_add(delta)?;
|
||||
let new_pages = self.current.checked_add(delta).map_err(|e| e.into())?;
|
||||
|
||||
if let Some(max) = self.max {
|
||||
if new_pages > max {
|
||||
return None;
|
||||
return Err(GrowError::ExceededMaxPagesForMemory(
|
||||
new_pages.0 as usize,
|
||||
max.0 as usize,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let mut new_memory =
|
||||
sys::Memory::with_size(new_pages.bytes().0 + DYNAMIC_GUARD_SIZE).ok()?;
|
||||
let mut new_memory = sys::Memory::with_size(new_pages.bytes().0 + DYNAMIC_GUARD_SIZE)
|
||||
.map_err(|e| e.into())?;
|
||||
|
||||
unsafe {
|
||||
new_memory
|
||||
.protect(0..new_pages.bytes().0, sys::Protect::ReadWrite)
|
||||
.ok()?;
|
||||
.map_err(|e| e.into())?;
|
||||
|
||||
new_memory.as_slice_mut()[..self.current.bytes().0]
|
||||
.copy_from_slice(&self.memory.as_slice()[..self.current.bytes().0]);
|
||||
@ -97,7 +101,7 @@ impl DynamicMemory {
|
||||
|
||||
let old_pages = self.current;
|
||||
self.current = new_pages;
|
||||
Some(old_pages)
|
||||
Ok(old_pages)
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
error::CreationError,
|
||||
error::{CreationError, GrowError},
|
||||
export::Export,
|
||||
import::IsExport,
|
||||
memory::dynamic::DYNAMIC_GUARD_SIZE,
|
||||
@ -89,8 +89,8 @@ impl Memory {
|
||||
self.desc
|
||||
}
|
||||
|
||||
/// Grow this memory by the specfied number of pages.
|
||||
pub fn grow(&self, delta: Pages) -> Option<Pages> {
|
||||
/// Grow this memory by the specified number of pages.
|
||||
pub fn grow(&self, delta: Pages) -> Result<Pages, GrowError> {
|
||||
match &self.variant {
|
||||
MemoryVariant::Unshared(unshared_mem) => unshared_mem.grow(delta),
|
||||
MemoryVariant::Shared(shared_mem) => shared_mem.grow(delta),
|
||||
@ -244,7 +244,7 @@ impl UnsharedMemory {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn grow(&self, delta: Pages) -> Option<Pages> {
|
||||
pub fn grow(&self, delta: Pages) -> Result<Pages, GrowError> {
|
||||
let mut storage = self.internal.storage.borrow_mut();
|
||||
|
||||
let mut local = self.internal.local.get();
|
||||
@ -292,7 +292,7 @@ impl SharedMemory {
|
||||
Ok(Self { desc })
|
||||
}
|
||||
|
||||
pub fn grow(&self, _delta: Pages) -> Option<Pages> {
|
||||
pub fn grow(&self, _delta: Pages) -> Result<Pages, GrowError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::error::GrowError;
|
||||
use crate::{
|
||||
error::CreationError,
|
||||
memory::static_::{SAFE_STATIC_GUARD_SIZE, SAFE_STATIC_HEAP_SIZE},
|
||||
@ -61,27 +62,30 @@ impl StaticMemory {
|
||||
self.current
|
||||
}
|
||||
|
||||
pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Option<Pages> {
|
||||
pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Result<Pages, GrowError> {
|
||||
if delta == Pages(0) {
|
||||
return Some(self.current);
|
||||
return Ok(self.current);
|
||||
}
|
||||
|
||||
let new_pages = self.current.checked_add(delta)?;
|
||||
let new_pages = self.current.checked_add(delta).map_err(|e| e.into())?;
|
||||
|
||||
if let Some(max) = self.max {
|
||||
if new_pages > max {
|
||||
return None;
|
||||
return Err(GrowError::ExceededMaxPagesForMemory(
|
||||
new_pages.0 as usize,
|
||||
max.0 as usize,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let _ = unsafe {
|
||||
self.memory
|
||||
.protect(
|
||||
self.current.bytes().0..new_pages.bytes().0,
|
||||
sys::Protect::ReadWrite,
|
||||
)
|
||||
.ok()?;
|
||||
}
|
||||
.map_err(|e| e.into())
|
||||
}?;
|
||||
|
||||
local.bound = new_pages.bytes().0;
|
||||
|
||||
@ -89,7 +93,7 @@ impl StaticMemory {
|
||||
|
||||
self.current = new_pages;
|
||||
|
||||
Some(old_pages)
|
||||
Ok(old_pages)
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
backend::{Backend, FuncResolver, ProtectedCaller},
|
||||
cache::{Artifact, Error as CacheError, WasmHash},
|
||||
cache::{Artifact, Error as CacheError},
|
||||
error,
|
||||
import::ImportObject,
|
||||
structures::{Map, TypedIndex},
|
||||
|
@ -56,6 +56,10 @@ where
|
||||
pub fn into_boxed_map(self) -> BoxedMap<K, V> {
|
||||
BoxedMap::new(self.elems.into_boxed_slice())
|
||||
}
|
||||
|
||||
pub fn into_vec(self) -> Vec<V> {
|
||||
self.elems
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Map<K, V>
|
||||
|
@ -1,3 +1,5 @@
|
||||
use crate::error::MemoryCreationError;
|
||||
use crate::error::MemoryProtectionError;
|
||||
use errno;
|
||||
use nix::libc;
|
||||
use page_size;
|
||||
@ -16,13 +18,13 @@ pub struct Memory {
|
||||
}
|
||||
|
||||
impl Memory {
|
||||
pub fn from_file_path<P>(path: P, protection: Protect) -> Result<Self, String>
|
||||
pub fn from_file_path<P>(path: P, protection: Protect) -> Result<Self, MemoryCreationError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let file = File::open(path).map_err(|e| e.to_string())?;
|
||||
let file = File::open(path)?;
|
||||
|
||||
let file_len = file.metadata().map_err(|e| e.to_string())?.len();
|
||||
let file_len = file.metadata()?.len();
|
||||
|
||||
let raw_fd = RawFd::from_file(file);
|
||||
|
||||
@ -38,7 +40,10 @@ impl Memory {
|
||||
};
|
||||
|
||||
if ptr == -1 as _ {
|
||||
Err(errno::errno().to_string())
|
||||
Err(MemoryCreationError::VirtualMemoryAllocationFailed(
|
||||
file_len as usize,
|
||||
errno::errno().to_string(),
|
||||
))
|
||||
} else {
|
||||
Ok(Self {
|
||||
ptr: ptr as *mut u8,
|
||||
@ -84,7 +89,7 @@ impl Memory {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_size(size: usize) -> Result<Self, String> {
|
||||
pub fn with_size(size: usize) -> Result<Self, MemoryCreationError> {
|
||||
if size == 0 {
|
||||
return Ok(Self {
|
||||
ptr: ptr::null_mut(),
|
||||
@ -108,7 +113,10 @@ impl Memory {
|
||||
};
|
||||
|
||||
if ptr == -1 as _ {
|
||||
Err(errno::errno().to_string())
|
||||
Err(MemoryCreationError::VirtualMemoryAllocationFailed(
|
||||
size,
|
||||
errno::errno().to_string(),
|
||||
))
|
||||
} else {
|
||||
Ok(Self {
|
||||
ptr: ptr as *mut u8,
|
||||
@ -123,7 +131,7 @@ impl Memory {
|
||||
&mut self,
|
||||
range: impl RangeBounds<usize>,
|
||||
protection: Protect,
|
||||
) -> Result<(), String> {
|
||||
) -> Result<(), MemoryProtectionError> {
|
||||
let protect = protection.to_protect_const();
|
||||
|
||||
let range_start = match range.start_bound() {
|
||||
@ -147,7 +155,11 @@ impl Memory {
|
||||
|
||||
let success = libc::mprotect(start as _, size, protect as i32);
|
||||
if success == -1 {
|
||||
Err(errno::errno().to_string())
|
||||
Err(MemoryProtectionError::ProtectionFailed(
|
||||
start as usize,
|
||||
size,
|
||||
errno::errno().to_string(),
|
||||
))
|
||||
} else {
|
||||
self.protection = protection;
|
||||
Ok(())
|
||||
|
@ -1,3 +1,5 @@
|
||||
use crate::error::MemoryCreationError;
|
||||
use crate::error::MemoryProtectionError;
|
||||
use page_size;
|
||||
use std::ops::{Bound, RangeBounds};
|
||||
use std::{ptr, slice};
|
||||
@ -44,7 +46,7 @@ impl Memory {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_size(size: usize) -> Result<Self, String> {
|
||||
pub fn with_size(size: usize) -> Result<Self, MemoryCreationError> {
|
||||
if size == 0 {
|
||||
return Ok(Self {
|
||||
ptr: ptr::null_mut(),
|
||||
@ -58,7 +60,10 @@ impl Memory {
|
||||
let ptr = unsafe { VirtualAlloc(ptr::null_mut(), size, MEM_RESERVE, PAGE_NOACCESS) };
|
||||
|
||||
if ptr.is_null() {
|
||||
Err("unable to allocate memory".to_string())
|
||||
Err(MemoryCreationError::VirtualMemoryAllocationFailed(
|
||||
size,
|
||||
"unable to allocate memory".to_string(),
|
||||
))
|
||||
} else {
|
||||
Ok(Self {
|
||||
ptr: ptr as *mut u8,
|
||||
@ -72,7 +77,7 @@ impl Memory {
|
||||
&mut self,
|
||||
range: impl RangeBounds<usize>,
|
||||
protect: Protect,
|
||||
) -> Result<(), String> {
|
||||
) -> Result<(), MemoryProtectionError> {
|
||||
let protect_const = protect.to_protect_const();
|
||||
|
||||
let range_start = match range.start_bound() {
|
||||
@ -98,7 +103,11 @@ impl Memory {
|
||||
let ptr = VirtualAlloc(start as _, size, MEM_COMMIT, protect_const);
|
||||
|
||||
if ptr.is_null() {
|
||||
Err("unable to protect memory".to_string())
|
||||
Err(MemoryProtectionError::ProtectionFailed(
|
||||
start as usize,
|
||||
size,
|
||||
"unable to protect memory".to_string(),
|
||||
))
|
||||
} else {
|
||||
self.protection = protect;
|
||||
Ok(())
|
||||
|
@ -11,6 +11,7 @@ mod anyfunc;
|
||||
|
||||
pub use self::anyfunc::Anyfunc;
|
||||
use self::anyfunc::AnyfuncTable;
|
||||
use crate::error::GrowError;
|
||||
|
||||
pub enum Element<'a> {
|
||||
Anyfunc(Anyfunc<'a>),
|
||||
@ -108,15 +109,15 @@ impl Table {
|
||||
}
|
||||
|
||||
/// Grow this table by `delta`.
|
||||
pub fn grow(&self, delta: u32) -> Option<u32> {
|
||||
pub fn grow(&self, delta: u32) -> Result<u32, GrowError> {
|
||||
if delta == 0 {
|
||||
return Some(self.size());
|
||||
return Ok(self.size());
|
||||
}
|
||||
|
||||
match &mut *self.storage.borrow_mut() {
|
||||
(TableStorage::Anyfunc(ref mut anyfunc_table), ref mut local) => {
|
||||
anyfunc_table.grow(delta, local)
|
||||
}
|
||||
(TableStorage::Anyfunc(ref mut anyfunc_table), ref mut local) => anyfunc_table
|
||||
.grow(delta, local)
|
||||
.ok_or(GrowError::TableGrowError),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ use crate::{
|
||||
types::{FuncSig, Type, WasmExternType},
|
||||
vm::Ctx,
|
||||
};
|
||||
use std::{cell::UnsafeCell, fmt, marker::PhantomData, mem, panic, ptr, sync::Arc};
|
||||
use std::{any::Any, cell::UnsafeCell, fmt, marker::PhantomData, mem, panic, ptr, sync::Arc};
|
||||
|
||||
thread_local! {
|
||||
pub static EARLY_TRAPPER: UnsafeCell<Option<Box<dyn UserTrapper>>> = UnsafeCell::new(None);
|
||||
@ -40,14 +40,14 @@ pub trait TrapEarly<Rets>
|
||||
where
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
fn report(self) -> Result<Rets, String>;
|
||||
fn report(self) -> Result<Rets, Box<dyn Any>>;
|
||||
}
|
||||
|
||||
impl<Rets> TrapEarly<Rets> for Rets
|
||||
where
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
fn report(self) -> Result<Rets, String> {
|
||||
fn report(self) -> Result<Rets, Box<dyn Any>> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
@ -55,10 +55,10 @@ where
|
||||
impl<Rets, E> TrapEarly<Rets> for Result<Rets, E>
|
||||
where
|
||||
Rets: WasmTypeList,
|
||||
E: fmt::Debug,
|
||||
E: Any,
|
||||
{
|
||||
fn report(self) -> Result<Rets, String> {
|
||||
self.map_err(|err| format!("Error: {:?}", err))
|
||||
fn report(self) -> Result<Rets, Box<dyn Any>> {
|
||||
self.map_err(|err| Box::new(err) as Box<dyn Any>)
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,25 +191,17 @@ macro_rules! impl_traits {
|
||||
extern fn wrap<$( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly<Rets>, FN: Fn( &mut Ctx $( ,$x )* ) -> Trap>( ctx: &mut Ctx $( ,$x: $x )* ) -> Rets::CStruct {
|
||||
let f: FN = unsafe { mem::transmute_copy(&()) };
|
||||
|
||||
let msg = match panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
let err = match panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
f( ctx $( ,$x )* ).report()
|
||||
})) {
|
||||
Ok(Ok(returns)) => return returns.into_c_struct(),
|
||||
Ok(Err(err)) => err,
|
||||
Err(err) => {
|
||||
if let Some(s) = err.downcast_ref::<&str>() {
|
||||
s.to_string()
|
||||
} else if let Some(s) = err.downcast_ref::<String>() {
|
||||
s.clone()
|
||||
} else {
|
||||
"a panic occurred, but no additional information is available".to_string()
|
||||
}
|
||||
},
|
||||
Err(err) => err,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
if let Some(early_trapper) = &*EARLY_TRAPPER.with(|ucell| ucell.get()) {
|
||||
early_trapper.do_early_trap(msg)
|
||||
early_trapper.do_early_trap(err)
|
||||
} else {
|
||||
eprintln!("panic handling not setup");
|
||||
std::process::exit(1)
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::error::PageError;
|
||||
use std::{
|
||||
fmt,
|
||||
ops::{Add, Sub},
|
||||
@ -11,12 +12,16 @@ const WASM_MAX_PAGES: usize = 65_536;
|
||||
pub struct Pages(pub u32);
|
||||
|
||||
impl Pages {
|
||||
pub fn checked_add(self, rhs: Pages) -> Option<Pages> {
|
||||
pub fn checked_add(self, rhs: Pages) -> Result<Pages, PageError> {
|
||||
let added = (self.0 as usize) + (rhs.0 as usize);
|
||||
if added <= WASM_MAX_PAGES {
|
||||
Some(Pages(added as u32))
|
||||
Ok(Pages(added as u32))
|
||||
} else {
|
||||
None
|
||||
Err(PageError::ExceededMaxPages(
|
||||
self.0 as usize,
|
||||
rhs.0 as usize,
|
||||
added,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,10 +20,9 @@ pub unsafe extern "C" fn local_static_memory_grow(
|
||||
let local_memory = *ctx.memories.add(memory_index.index());
|
||||
let memory = (*local_memory).memory as *mut StaticMemory;
|
||||
|
||||
if let Some(old) = (*memory).grow(delta, &mut *local_memory) {
|
||||
old.0 as i32
|
||||
} else {
|
||||
-1
|
||||
match (*memory).grow(delta, &mut *local_memory) {
|
||||
Ok(old) => old.0 as i32,
|
||||
Err(_) => -1,
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,10 +44,9 @@ pub unsafe extern "C" fn local_dynamic_memory_grow(
|
||||
let local_memory = *ctx.memories.add(memory_index.index());
|
||||
let memory = (*local_memory).memory as *mut DynamicMemory;
|
||||
|
||||
if let Some(old) = (*memory).grow(delta, &mut *local_memory) {
|
||||
old.0 as i32
|
||||
} else {
|
||||
-1
|
||||
match (*memory).grow(delta, &mut *local_memory) {
|
||||
Ok(old) => old.0 as i32,
|
||||
Err(_) => -1,
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,10 +72,9 @@ pub unsafe extern "C" fn imported_static_memory_grow(
|
||||
let local_memory = *ctx.imported_memories.add(import_memory_index.index());
|
||||
let memory = (*local_memory).memory as *mut StaticMemory;
|
||||
|
||||
if let Some(old) = (*memory).grow(delta, &mut *local_memory) {
|
||||
old.0 as i32
|
||||
} else {
|
||||
-1
|
||||
match (*memory).grow(delta, &mut *local_memory) {
|
||||
Ok(old) => old.0 as i32,
|
||||
Err(_) => -1,
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,10 +96,9 @@ pub unsafe extern "C" fn imported_dynamic_memory_grow(
|
||||
let local_memory = *ctx.imported_memories.add(memory_index.index());
|
||||
let memory = (*local_memory).memory as *mut DynamicMemory;
|
||||
|
||||
if let Some(old) = (*memory).grow(delta, &mut *local_memory) {
|
||||
old.0 as i32
|
||||
} else {
|
||||
-1
|
||||
match (*memory).grow(delta, &mut *local_memory) {
|
||||
Ok(old) => old.0 as i32,
|
||||
Err(_) => -1,
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user