runtime: use anyhow::Error instead of Box<dyn std::error::Error...>
This commit is contained in:
@@ -12,6 +12,7 @@ use crate::vmcontext::{
|
|||||||
VMInterrupts, VMMemoryDefinition, VMMemoryImport, VMTableDefinition, VMTableImport,
|
VMInterrupts, VMMemoryDefinition, VMMemoryImport, VMTableDefinition, VMTableImport,
|
||||||
};
|
};
|
||||||
use crate::{ExportFunction, ExportGlobal, ExportMemory, ExportTable, Store};
|
use crate::{ExportFunction, ExportGlobal, ExportMemory, ExportTable, Store};
|
||||||
|
use anyhow::Error;
|
||||||
use memoffset::offset_of;
|
use memoffset::offset_of;
|
||||||
use more_asserts::assert_lt;
|
use more_asserts::assert_lt;
|
||||||
use std::alloc::Layout;
|
use std::alloc::Layout;
|
||||||
@@ -348,7 +349,11 @@ impl Instance {
|
|||||||
/// Returns `None` if memory can't be grown by the specified amount
|
/// Returns `None` if memory can't be grown by the specified amount
|
||||||
/// of pages. Returns `Some` with the old size in bytes if growth was
|
/// of pages. Returns `Some` with the old size in bytes if growth was
|
||||||
/// successful.
|
/// successful.
|
||||||
pub(crate) fn memory_grow(&mut self, index: MemoryIndex, delta: u64) -> Option<usize> {
|
pub(crate) fn memory_grow(
|
||||||
|
&mut self,
|
||||||
|
index: MemoryIndex,
|
||||||
|
delta: u64,
|
||||||
|
) -> Result<Option<usize>, Error> {
|
||||||
let (idx, instance) = if let Some(idx) = self.module.defined_memory_index(index) {
|
let (idx, instance) = if let Some(idx) = self.module.defined_memory_index(index) {
|
||||||
(idx, self)
|
(idx, self)
|
||||||
} else {
|
} else {
|
||||||
@@ -387,7 +392,7 @@ impl Instance {
|
|||||||
table_index: TableIndex,
|
table_index: TableIndex,
|
||||||
delta: u32,
|
delta: u32,
|
||||||
init_value: TableElement,
|
init_value: TableElement,
|
||||||
) -> Option<u32> {
|
) -> Result<Option<u32>, Error> {
|
||||||
let (defined_table_index, instance) =
|
let (defined_table_index, instance) =
|
||||||
self.get_defined_table_index_and_instance(table_index);
|
self.get_defined_table_index_and_instance(table_index);
|
||||||
instance.defined_table_grow(defined_table_index, delta, init_value)
|
instance.defined_table_grow(defined_table_index, delta, init_value)
|
||||||
@@ -398,7 +403,7 @@ impl Instance {
|
|||||||
table_index: DefinedTableIndex,
|
table_index: DefinedTableIndex,
|
||||||
delta: u32,
|
delta: u32,
|
||||||
init_value: TableElement,
|
init_value: TableElement,
|
||||||
) -> Option<u32> {
|
) -> Result<Option<u32>, Error> {
|
||||||
let store = unsafe { &mut *self.store() };
|
let store = unsafe { &mut *self.store() };
|
||||||
let table = self
|
let table = self
|
||||||
.tables
|
.tables
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
|
|
||||||
use std::error::Error;
|
use anyhow::Error;
|
||||||
|
|
||||||
mod export;
|
mod export;
|
||||||
mod externref;
|
mod externref;
|
||||||
@@ -91,15 +91,25 @@ pub unsafe trait Store {
|
|||||||
) -> (&mut VMExternRefActivationsTable, &dyn ModuleInfoLookup);
|
) -> (&mut VMExternRefActivationsTable, &dyn ModuleInfoLookup);
|
||||||
|
|
||||||
/// Callback invoked to allow the store's resource limiter to reject a memory grow operation.
|
/// Callback invoked to allow the store's resource limiter to reject a memory grow operation.
|
||||||
fn memory_growing(&mut self, current: usize, desired: usize, maximum: Option<usize>) -> bool;
|
fn memory_growing(
|
||||||
|
&mut self,
|
||||||
|
current: usize,
|
||||||
|
desired: usize,
|
||||||
|
maximum: Option<usize>,
|
||||||
|
) -> Result<bool, Error>;
|
||||||
/// Callback invoked to notify the store's resource limiter that a memory grow operation has
|
/// Callback invoked to notify the store's resource limiter that a memory grow operation has
|
||||||
/// failed.
|
/// failed.
|
||||||
fn memory_grow_failed(&mut self, error: &anyhow::Error);
|
fn memory_grow_failed(&mut self, error: &Error);
|
||||||
/// Callback invoked to allow the store's resource limiter to reject a table grow operation.
|
/// Callback invoked to allow the store's resource limiter to reject a table grow operation.
|
||||||
fn table_growing(&mut self, current: u32, desired: u32, maximum: Option<u32>) -> bool;
|
fn table_growing(
|
||||||
|
&mut self,
|
||||||
|
current: u32,
|
||||||
|
desired: u32,
|
||||||
|
maximum: Option<u32>,
|
||||||
|
) -> Result<bool, Error>;
|
||||||
|
|
||||||
/// Callback invoked whenever fuel runs out by a wasm instance. If an error
|
/// Callback invoked whenever fuel runs out by a wasm instance. If an error
|
||||||
/// is returned that's raised as a trap. Otherwise wasm execution will
|
/// is returned that's raised as a trap. Otherwise wasm execution will
|
||||||
/// continue as normal.
|
/// continue as normal.
|
||||||
fn out_of_gas(&mut self) -> Result<(), Box<dyn Error + Send + Sync>>;
|
fn out_of_gas(&mut self) -> Result<(), Error>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -193,8 +193,9 @@ pub unsafe extern "C" fn wasmtime_memory32_grow(
|
|||||||
let instance = (*vmctx).instance_mut();
|
let instance = (*vmctx).instance_mut();
|
||||||
let memory_index = MemoryIndex::from_u32(memory_index);
|
let memory_index = MemoryIndex::from_u32(memory_index);
|
||||||
match instance.memory_grow(memory_index, delta) {
|
match instance.memory_grow(memory_index, delta) {
|
||||||
Some(size_in_bytes) => size_in_bytes / (wasmtime_environ::WASM_PAGE_SIZE as usize),
|
Ok(Some(size_in_bytes)) => size_in_bytes / (wasmtime_environ::WASM_PAGE_SIZE as usize),
|
||||||
None => usize::max_value(),
|
Ok(None) => usize::max_value(),
|
||||||
|
Err(err) => crate::traphandlers::raise_user_trap(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,9 +221,11 @@ pub unsafe extern "C" fn wasmtime_table_grow(
|
|||||||
init_value.into()
|
init_value.into()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
instance
|
match instance.table_grow(table_index, delta, element) {
|
||||||
.table_grow(table_index, delta, element)
|
Ok(Some(r)) => r,
|
||||||
.unwrap_or(-1_i32 as u32)
|
Ok(None) => -1_i32 as u32,
|
||||||
|
Err(err) => crate::traphandlers::raise_user_trap(err),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation of `table.fill`.
|
/// Implementation of `table.fill`.
|
||||||
@@ -436,15 +439,6 @@ pub unsafe extern "C" fn wasmtime_externref_global_set(
|
|||||||
drop(old);
|
drop(old);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Unimplemented(&'static str);
|
|
||||||
impl std::error::Error for Unimplemented {}
|
|
||||||
impl std::fmt::Display for Unimplemented {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
|
||||||
write!(f, "unimplemented: {}", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implementation of `memory.atomic.notify` for locally defined memories.
|
/// Implementation of `memory.atomic.notify` for locally defined memories.
|
||||||
pub unsafe extern "C" fn wasmtime_memory_atomic_notify(
|
pub unsafe extern "C" fn wasmtime_memory_atomic_notify(
|
||||||
vmctx: *mut VMContext,
|
vmctx: *mut VMContext,
|
||||||
@@ -460,9 +454,9 @@ pub unsafe extern "C" fn wasmtime_memory_atomic_notify(
|
|||||||
// just to be sure.
|
// just to be sure.
|
||||||
let addr_to_check = addr.checked_add(4).unwrap();
|
let addr_to_check = addr.checked_add(4).unwrap();
|
||||||
validate_atomic_addr(instance, memory, addr_to_check).and_then(|()| {
|
validate_atomic_addr(instance, memory, addr_to_check).and_then(|()| {
|
||||||
Err(Trap::User(Box::new(Unimplemented(
|
Err(Trap::User(anyhow::anyhow!(
|
||||||
"wasm atomics (fn wasmtime_memory_atomic_notify) unsupported",
|
"unimplemented: wasm atomics (fn wasmtime_memory_atomic_notify) unsupported",
|
||||||
))))
|
)))
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
match result {
|
match result {
|
||||||
@@ -486,9 +480,9 @@ pub unsafe extern "C" fn wasmtime_memory_atomic_wait32(
|
|||||||
// but we still double-check
|
// but we still double-check
|
||||||
let addr_to_check = addr.checked_add(4).unwrap();
|
let addr_to_check = addr.checked_add(4).unwrap();
|
||||||
validate_atomic_addr(instance, memory, addr_to_check).and_then(|()| {
|
validate_atomic_addr(instance, memory, addr_to_check).and_then(|()| {
|
||||||
Err(Trap::User(Box::new(Unimplemented(
|
Err(Trap::User(anyhow::anyhow!(
|
||||||
"wasm atomics (fn wasmtime_memory_atomic_wait32) unsupported",
|
"unimplemented: wasm atomics (fn wasmtime_memory_atomic_wait32) unsupported",
|
||||||
))))
|
)))
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
match result {
|
match result {
|
||||||
@@ -512,9 +506,9 @@ pub unsafe extern "C" fn wasmtime_memory_atomic_wait64(
|
|||||||
// but we still double-check
|
// but we still double-check
|
||||||
let addr_to_check = addr.checked_add(8).unwrap();
|
let addr_to_check = addr.checked_add(8).unwrap();
|
||||||
validate_atomic_addr(instance, memory, addr_to_check).and_then(|()| {
|
validate_atomic_addr(instance, memory, addr_to_check).and_then(|()| {
|
||||||
Err(Trap::User(Box::new(Unimplemented(
|
Err(Trap::User(anyhow::anyhow!(
|
||||||
"wasm atomics (fn wasmtime_memory_atomic_wait64) unsupported",
|
"unimplemented: wasm atomics (fn wasmtime_memory_atomic_wait64) unsupported",
|
||||||
))))
|
)))
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
match result {
|
match result {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
use crate::mmap::Mmap;
|
use crate::mmap::Mmap;
|
||||||
use crate::vmcontext::VMMemoryDefinition;
|
use crate::vmcontext::VMMemoryDefinition;
|
||||||
use crate::Store;
|
use crate::Store;
|
||||||
|
use anyhow::Error;
|
||||||
use anyhow::{bail, format_err, Result};
|
use anyhow::{bail, format_err, Result};
|
||||||
use more_asserts::{assert_ge, assert_le};
|
use more_asserts::{assert_ge, assert_le};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
@@ -315,7 +316,7 @@ impl Memory {
|
|||||||
// calculation overflowed. This means that the `minimum` we're informing
|
// calculation overflowed. This means that the `minimum` we're informing
|
||||||
// the limiter is lossy and may not be 100% accurate, but for now the
|
// the limiter is lossy and may not be 100% accurate, but for now the
|
||||||
// expected uses of limiter means that's ok.
|
// expected uses of limiter means that's ok.
|
||||||
if !store.memory_growing(0, minimum.unwrap_or(absolute_max), maximum) {
|
if !store.memory_growing(0, minimum.unwrap_or(absolute_max), maximum)? {
|
||||||
bail!(
|
bail!(
|
||||||
"memory minimum size of {} pages exceeds memory limits",
|
"memory minimum size of {} pages exceeds memory limits",
|
||||||
plan.memory.minimum
|
plan.memory.minimum
|
||||||
@@ -377,11 +378,15 @@ impl Memory {
|
|||||||
///
|
///
|
||||||
/// Generally, prefer using `InstanceHandle::memory_grow`, which encapsulates
|
/// Generally, prefer using `InstanceHandle::memory_grow`, which encapsulates
|
||||||
/// this unsafety.
|
/// this unsafety.
|
||||||
pub unsafe fn grow(&mut self, delta_pages: u64, store: &mut dyn Store) -> Option<usize> {
|
pub unsafe fn grow(
|
||||||
|
&mut self,
|
||||||
|
delta_pages: u64,
|
||||||
|
store: &mut dyn Store,
|
||||||
|
) -> Result<Option<usize>, Error> {
|
||||||
let old_byte_size = self.byte_size();
|
let old_byte_size = self.byte_size();
|
||||||
// Wasm spec: when growing by 0 pages, always return the current size.
|
// Wasm spec: when growing by 0 pages, always return the current size.
|
||||||
if delta_pages == 0 {
|
if delta_pages == 0 {
|
||||||
return Some(old_byte_size);
|
return Ok(Some(old_byte_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
// largest wasm-page-aligned region of memory it is possible to
|
// largest wasm-page-aligned region of memory it is possible to
|
||||||
@@ -402,15 +407,15 @@ impl Memory {
|
|||||||
|
|
||||||
let maximum = self.maximum_byte_size();
|
let maximum = self.maximum_byte_size();
|
||||||
// Store limiter gets first chance to reject memory_growing.
|
// Store limiter gets first chance to reject memory_growing.
|
||||||
if !store.memory_growing(old_byte_size, new_byte_size, maximum) {
|
if !store.memory_growing(old_byte_size, new_byte_size, maximum)? {
|
||||||
return None;
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Never exceed maximum, even if limiter permitted it.
|
// Never exceed maximum, even if limiter permitted it.
|
||||||
if let Some(max) = maximum {
|
if let Some(max) = maximum {
|
||||||
if new_byte_size > max {
|
if new_byte_size > max {
|
||||||
store.memory_grow_failed(&format_err!("Memory maximum size exceeded"));
|
store.memory_grow_failed(&format_err!("Memory maximum size exceeded"));
|
||||||
return None;
|
return Ok(None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,7 +423,10 @@ impl Memory {
|
|||||||
{
|
{
|
||||||
if self.is_static() {
|
if self.is_static() {
|
||||||
// Reset any faulted guard pages before growing the memory.
|
// Reset any faulted guard pages before growing the memory.
|
||||||
self.reset_guard_pages().ok()?;
|
if let Err(e) = self.reset_guard_pages() {
|
||||||
|
store.memory_grow_failed(&e);
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,24 +440,27 @@ impl Memory {
|
|||||||
// Never exceed static memory size
|
// Never exceed static memory size
|
||||||
if new_byte_size > base.len() {
|
if new_byte_size > base.len() {
|
||||||
store.memory_grow_failed(&format_err!("static memory size exceeded"));
|
store.memory_grow_failed(&format_err!("static memory size exceeded"));
|
||||||
return None;
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Operating system can fail to make memory accessible
|
// Operating system can fail to make memory accessible
|
||||||
let r = make_accessible(
|
if let Err(e) = make_accessible(
|
||||||
base.as_mut_ptr().add(old_byte_size),
|
base.as_mut_ptr().add(old_byte_size),
|
||||||
new_byte_size - old_byte_size,
|
new_byte_size - old_byte_size,
|
||||||
);
|
) {
|
||||||
r.map_err(|e| store.memory_grow_failed(&e)).ok()?;
|
store.memory_grow_failed(&e);
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
*size = new_byte_size;
|
*size = new_byte_size;
|
||||||
}
|
}
|
||||||
Memory::Dynamic(mem) => {
|
Memory::Dynamic(mem) => {
|
||||||
let r = mem.grow_to(new_byte_size);
|
if let Err(e) = mem.grow_to(new_byte_size) {
|
||||||
r.map_err(|e| store.memory_grow_failed(&e)).ok()?;
|
store.memory_grow_failed(&e);
|
||||||
|
return Ok(None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(old_byte_size)
|
}
|
||||||
|
Ok(Some(old_byte_size))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a `VMMemoryDefinition` for exposing the memory to compiled wasm code.
|
/// Return a `VMMemoryDefinition` for exposing the memory to compiled wasm code.
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use crate::vmcontext::{VMCallerCheckedAnyfunc, VMTableDefinition};
|
use crate::vmcontext::{VMCallerCheckedAnyfunc, VMTableDefinition};
|
||||||
use crate::{Store, Trap, VMExternRef};
|
use crate::{Store, Trap, VMExternRef};
|
||||||
|
use anyhow::Error;
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
@@ -168,7 +169,7 @@ impl Table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn limit_new(plan: &TablePlan, store: &mut dyn Store) -> Result<()> {
|
fn limit_new(plan: &TablePlan, store: &mut dyn Store) -> Result<()> {
|
||||||
if !store.table_growing(0, plan.table.minimum, plan.table.maximum) {
|
if !store.table_growing(0, plan.table.minimum, plan.table.maximum)? {
|
||||||
bail!(
|
bail!(
|
||||||
"table minimum size of {} elements exceeds table limits",
|
"table minimum size of {} elements exceeds table limits",
|
||||||
plan.table.minimum
|
plan.table.minimum
|
||||||
@@ -288,17 +289,20 @@ impl Table {
|
|||||||
delta: u32,
|
delta: u32,
|
||||||
init_value: TableElement,
|
init_value: TableElement,
|
||||||
store: &mut dyn Store,
|
store: &mut dyn Store,
|
||||||
) -> Option<u32> {
|
) -> Result<Option<u32>, Error> {
|
||||||
let old_size = self.size();
|
let old_size = self.size();
|
||||||
let new_size = old_size.checked_add(delta)?;
|
let new_size = match old_size.checked_add(delta) {
|
||||||
|
Some(s) => s,
|
||||||
|
None => return Ok(None),
|
||||||
|
};
|
||||||
|
|
||||||
if !store.table_growing(old_size, new_size, self.maximum()) {
|
if !store.table_growing(old_size, new_size, self.maximum())? {
|
||||||
return None;
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(max) = self.maximum() {
|
if let Some(max) = self.maximum() {
|
||||||
if new_size > max {
|
if new_size > max {
|
||||||
return None;
|
return Ok(None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +324,7 @@ impl Table {
|
|||||||
self.fill(old_size, init_value, delta)
|
self.fill(old_size, init_value, delta)
|
||||||
.expect("table should not be out of bounds");
|
.expect("table should not be out of bounds");
|
||||||
|
|
||||||
Some(old_size)
|
Ok(Some(old_size))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get reference to the specified element.
|
/// Get reference to the specified element.
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
//! signalhandling mechanisms.
|
//! signalhandling mechanisms.
|
||||||
|
|
||||||
use crate::{VMContext, VMInterrupts};
|
use crate::{VMContext, VMInterrupts};
|
||||||
|
use anyhow::Error;
|
||||||
use backtrace::Backtrace;
|
use backtrace::Backtrace;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::{Cell, UnsafeCell};
|
use std::cell::{Cell, UnsafeCell};
|
||||||
use std::error::Error;
|
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::atomic::Ordering::SeqCst;
|
use std::sync::atomic::Ordering::SeqCst;
|
||||||
@@ -80,7 +80,7 @@ pub fn init_traps(is_wasm_pc: fn(usize) -> bool) {
|
|||||||
/// Only safe to call when wasm code is on the stack, aka `catch_traps` must
|
/// Only safe to call when wasm code is on the stack, aka `catch_traps` must
|
||||||
/// have been previously called. Additionally no Rust destructors can be on the
|
/// have been previously called. Additionally no Rust destructors can be on the
|
||||||
/// stack. They will be skipped and not executed.
|
/// stack. They will be skipped and not executed.
|
||||||
pub unsafe fn raise_user_trap(data: Box<dyn Error + Send + Sync>) -> ! {
|
pub unsafe fn raise_user_trap(data: Error) -> ! {
|
||||||
tls::with(|info| info.unwrap().unwind_with(UnwindReason::UserTrap(data)))
|
tls::with(|info| info.unwrap().unwind_with(UnwindReason::UserTrap(data)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +114,7 @@ pub unsafe fn resume_panic(payload: Box<dyn Any + Send>) -> ! {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Trap {
|
pub enum Trap {
|
||||||
/// A user-raised trap through `raise_user_trap`.
|
/// A user-raised trap through `raise_user_trap`.
|
||||||
User(Box<dyn Error + Send + Sync>),
|
User(Error),
|
||||||
|
|
||||||
/// A trap raised from jit code
|
/// A trap raised from jit code
|
||||||
Jit {
|
Jit {
|
||||||
@@ -206,7 +206,7 @@ pub struct CallThreadState {
|
|||||||
|
|
||||||
enum UnwindReason {
|
enum UnwindReason {
|
||||||
Panic(Box<dyn Any + Send>),
|
Panic(Box<dyn Any + Send>),
|
||||||
UserTrap(Box<dyn Error + Send + Sync>),
|
UserTrap(Error),
|
||||||
LibTrap(Trap),
|
LibTrap(Trap),
|
||||||
JitTrap { backtrace: Backtrace, pc: usize },
|
JitTrap { backtrace: Backtrace, pc: usize },
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user