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,
|
||||
};
|
||||
use crate::{ExportFunction, ExportGlobal, ExportMemory, ExportTable, Store};
|
||||
use anyhow::Error;
|
||||
use memoffset::offset_of;
|
||||
use more_asserts::assert_lt;
|
||||
use std::alloc::Layout;
|
||||
@@ -348,7 +349,11 @@ impl Instance {
|
||||
/// 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
|
||||
/// 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) {
|
||||
(idx, self)
|
||||
} else {
|
||||
@@ -387,7 +392,7 @@ impl Instance {
|
||||
table_index: TableIndex,
|
||||
delta: u32,
|
||||
init_value: TableElement,
|
||||
) -> Option<u32> {
|
||||
) -> Result<Option<u32>, Error> {
|
||||
let (defined_table_index, instance) =
|
||||
self.get_defined_table_index_and_instance(table_index);
|
||||
instance.defined_table_grow(defined_table_index, delta, init_value)
|
||||
@@ -398,7 +403,7 @@ impl Instance {
|
||||
table_index: DefinedTableIndex,
|
||||
delta: u32,
|
||||
init_value: TableElement,
|
||||
) -> Option<u32> {
|
||||
) -> Result<Option<u32>, Error> {
|
||||
let store = unsafe { &mut *self.store() };
|
||||
let table = self
|
||||
.tables
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
)
|
||||
)]
|
||||
|
||||
use std::error::Error;
|
||||
use anyhow::Error;
|
||||
|
||||
mod export;
|
||||
mod externref;
|
||||
@@ -91,15 +91,25 @@ pub unsafe trait Store {
|
||||
) -> (&mut VMExternRefActivationsTable, &dyn ModuleInfoLookup);
|
||||
|
||||
/// 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
|
||||
/// 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.
|
||||
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
|
||||
/// is returned that's raised as a trap. Otherwise wasm execution will
|
||||
/// 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 memory_index = MemoryIndex::from_u32(memory_index);
|
||||
match instance.memory_grow(memory_index, delta) {
|
||||
Some(size_in_bytes) => size_in_bytes / (wasmtime_environ::WASM_PAGE_SIZE as usize),
|
||||
None => usize::max_value(),
|
||||
Ok(Some(size_in_bytes)) => size_in_bytes / (wasmtime_environ::WASM_PAGE_SIZE as usize),
|
||||
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()
|
||||
}
|
||||
};
|
||||
instance
|
||||
.table_grow(table_index, delta, element)
|
||||
.unwrap_or(-1_i32 as u32)
|
||||
match instance.table_grow(table_index, delta, element) {
|
||||
Ok(Some(r)) => r,
|
||||
Ok(None) => -1_i32 as u32,
|
||||
Err(err) => crate::traphandlers::raise_user_trap(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of `table.fill`.
|
||||
@@ -436,15 +439,6 @@ pub unsafe extern "C" fn wasmtime_externref_global_set(
|
||||
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.
|
||||
pub unsafe extern "C" fn wasmtime_memory_atomic_notify(
|
||||
vmctx: *mut VMContext,
|
||||
@@ -460,9 +454,9 @@ pub unsafe extern "C" fn wasmtime_memory_atomic_notify(
|
||||
// just to be sure.
|
||||
let addr_to_check = addr.checked_add(4).unwrap();
|
||||
validate_atomic_addr(instance, memory, addr_to_check).and_then(|()| {
|
||||
Err(Trap::User(Box::new(Unimplemented(
|
||||
"wasm atomics (fn wasmtime_memory_atomic_notify) unsupported",
|
||||
))))
|
||||
Err(Trap::User(anyhow::anyhow!(
|
||||
"unimplemented: wasm atomics (fn wasmtime_memory_atomic_notify) unsupported",
|
||||
)))
|
||||
})
|
||||
};
|
||||
match result {
|
||||
@@ -486,9 +480,9 @@ pub unsafe extern "C" fn wasmtime_memory_atomic_wait32(
|
||||
// but we still double-check
|
||||
let addr_to_check = addr.checked_add(4).unwrap();
|
||||
validate_atomic_addr(instance, memory, addr_to_check).and_then(|()| {
|
||||
Err(Trap::User(Box::new(Unimplemented(
|
||||
"wasm atomics (fn wasmtime_memory_atomic_wait32) unsupported",
|
||||
))))
|
||||
Err(Trap::User(anyhow::anyhow!(
|
||||
"unimplemented: wasm atomics (fn wasmtime_memory_atomic_wait32) unsupported",
|
||||
)))
|
||||
})
|
||||
};
|
||||
match result {
|
||||
@@ -512,9 +506,9 @@ pub unsafe extern "C" fn wasmtime_memory_atomic_wait64(
|
||||
// but we still double-check
|
||||
let addr_to_check = addr.checked_add(8).unwrap();
|
||||
validate_atomic_addr(instance, memory, addr_to_check).and_then(|()| {
|
||||
Err(Trap::User(Box::new(Unimplemented(
|
||||
"wasm atomics (fn wasmtime_memory_atomic_wait64) unsupported",
|
||||
))))
|
||||
Err(Trap::User(anyhow::anyhow!(
|
||||
"unimplemented: wasm atomics (fn wasmtime_memory_atomic_wait64) unsupported",
|
||||
)))
|
||||
})
|
||||
};
|
||||
match result {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
use crate::mmap::Mmap;
|
||||
use crate::vmcontext::VMMemoryDefinition;
|
||||
use crate::Store;
|
||||
use anyhow::Error;
|
||||
use anyhow::{bail, format_err, Result};
|
||||
use more_asserts::{assert_ge, assert_le};
|
||||
use std::convert::TryFrom;
|
||||
@@ -315,7 +316,7 @@ impl Memory {
|
||||
// calculation overflowed. This means that the `minimum` we're informing
|
||||
// the limiter is lossy and may not be 100% accurate, but for now the
|
||||
// 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!(
|
||||
"memory minimum size of {} pages exceeds memory limits",
|
||||
plan.memory.minimum
|
||||
@@ -377,11 +378,15 @@ impl Memory {
|
||||
///
|
||||
/// Generally, prefer using `InstanceHandle::memory_grow`, which encapsulates
|
||||
/// 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();
|
||||
// Wasm spec: when growing by 0 pages, always return the current size.
|
||||
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
|
||||
@@ -402,15 +407,15 @@ impl Memory {
|
||||
|
||||
let maximum = self.maximum_byte_size();
|
||||
// Store limiter gets first chance to reject memory_growing.
|
||||
if !store.memory_growing(old_byte_size, new_byte_size, maximum) {
|
||||
return None;
|
||||
if !store.memory_growing(old_byte_size, new_byte_size, maximum)? {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Never exceed maximum, even if limiter permitted it.
|
||||
if let Some(max) = maximum {
|
||||
if new_byte_size > max {
|
||||
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() {
|
||||
// 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
|
||||
if new_byte_size > base.len() {
|
||||
store.memory_grow_failed(&format_err!("static memory size exceeded"));
|
||||
return None;
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// 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),
|
||||
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;
|
||||
}
|
||||
Memory::Dynamic(mem) => {
|
||||
let r = mem.grow_to(new_byte_size);
|
||||
r.map_err(|e| store.memory_grow_failed(&e)).ok()?;
|
||||
if let Err(e) = mem.grow_to(new_byte_size) {
|
||||
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.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
use crate::vmcontext::{VMCallerCheckedAnyfunc, VMTableDefinition};
|
||||
use crate::{Store, Trap, VMExternRef};
|
||||
use anyhow::Error;
|
||||
use anyhow::{bail, Result};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::ops::Range;
|
||||
@@ -168,7 +169,7 @@ impl Table {
|
||||
}
|
||||
|
||||
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!(
|
||||
"table minimum size of {} elements exceeds table limits",
|
||||
plan.table.minimum
|
||||
@@ -288,17 +289,20 @@ impl Table {
|
||||
delta: u32,
|
||||
init_value: TableElement,
|
||||
store: &mut dyn Store,
|
||||
) -> Option<u32> {
|
||||
) -> Result<Option<u32>, Error> {
|
||||
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()) {
|
||||
return None;
|
||||
if !store.table_growing(old_size, new_size, self.maximum())? {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
if let Some(max) = self.maximum() {
|
||||
if new_size > max {
|
||||
return None;
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,7 +324,7 @@ impl Table {
|
||||
self.fill(old_size, init_value, delta)
|
||||
.expect("table should not be out of bounds");
|
||||
|
||||
Some(old_size)
|
||||
Ok(Some(old_size))
|
||||
}
|
||||
|
||||
/// Get reference to the specified element.
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
//! signalhandling mechanisms.
|
||||
|
||||
use crate::{VMContext, VMInterrupts};
|
||||
use anyhow::Error;
|
||||
use backtrace::Backtrace;
|
||||
use std::any::Any;
|
||||
use std::cell::{Cell, UnsafeCell};
|
||||
use std::error::Error;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ptr;
|
||||
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
|
||||
/// have been previously called. Additionally no Rust destructors can be on the
|
||||
/// 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)))
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ pub unsafe fn resume_panic(payload: Box<dyn Any + Send>) -> ! {
|
||||
#[derive(Debug)]
|
||||
pub enum Trap {
|
||||
/// A user-raised trap through `raise_user_trap`.
|
||||
User(Box<dyn Error + Send + Sync>),
|
||||
User(Error),
|
||||
|
||||
/// A trap raised from jit code
|
||||
Jit {
|
||||
@@ -206,7 +206,7 @@ pub struct CallThreadState {
|
||||
|
||||
enum UnwindReason {
|
||||
Panic(Box<dyn Any + Send>),
|
||||
UserTrap(Box<dyn Error + Send + Sync>),
|
||||
UserTrap(Error),
|
||||
LibTrap(Trap),
|
||||
JitTrap { backtrace: Backtrace, pc: usize },
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user