Skip to content

Commit c3627c1

Browse files
authored
Redesign Store and StoreInner internal error handling (#1679)
* redesign Store and StoreInner internal error handling * adjust Wasmi executor for redesigned Store[Inner] * fix intradoc links * apply rustfmt
1 parent 2b3a14c commit c3627c1

File tree

10 files changed

+432
-174
lines changed

10 files changed

+432
-174
lines changed

crates/wasmi/src/engine/executor/instrs/call.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
},
1111
func::{FuncEntity, HostFuncEntity},
1212
ir::{index, Op, Slot, SlotSpan},
13-
store::{CallHooks, PrunedStore, StoreInner},
13+
store::{CallHooks, PrunedStore, StoreError, StoreInner},
1414
Error,
1515
Func,
1616
Instance,
@@ -42,16 +42,21 @@ pub fn dispatch_host_func(
4242
usize::from(len_params),
4343
usize::from(len_results),
4444
);
45-
store
46-
.call_host_func(&host_func, instance, params_results, call_hooks)
47-
.inspect_err(|_error| {
45+
match store.call_host_func(&host_func, instance, params_results, call_hooks) {
46+
Err(StoreError::Internal(error)) => {
47+
panic!("`call.host`: internal interpreter error: {error}")
48+
}
49+
Err(StoreError::External(error)) => {
4850
// Note: We drop the values that have been temporarily added to
4951
// the stack to act as parameter and result buffer for the
5052
// called host function. Since the host function failed we
5153
// need to clean up the temporary buffer values here.
5254
// This is required for resumable calls to work properly.
5355
value_stack.drop(usize::from(max_inout));
54-
})?;
56+
return Err(error);
57+
}
58+
_ => {}
59+
}
5560
Ok((len_params, len_results))
5661
}
5762

crates/wasmi/src/engine/executor/instrs/memory.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{
77
Op,
88
Slot,
99
},
10-
store::{PrunedStore, StoreInner},
10+
store::{PrunedStore, StoreError, StoreInner},
1111
Error,
1212
TrapCode,
1313
};
@@ -46,7 +46,7 @@ impl Executor<'_> {
4646
/// Executes an [`Op::DataDrop`].
4747
pub fn execute_data_drop(&mut self, store: &mut StoreInner, segment_index: Data) {
4848
let segment = self.get_data_segment(segment_index);
49-
store.resolve_data_segment_mut(&segment).drop_bytes();
49+
store.resolve_data_mut(&segment).drop_bytes();
5050
self.next_instr();
5151
}
5252

@@ -88,20 +88,24 @@ impl Executor<'_> {
8888
unsafe { self.cache.update_memory(store.inner_mut()) };
8989
return_value
9090
}
91-
Err(MemoryError::OutOfBoundsGrowth | MemoryError::OutOfSystemMemory) => {
91+
Err(StoreError::External(
92+
MemoryError::OutOfBoundsGrowth | MemoryError::OutOfSystemMemory,
93+
)) => {
9294
let memory_ty = store.inner().resolve_memory(&memory).ty();
9395
match memory_ty.is_64() {
9496
true => u64::MAX,
9597
false => u64::from(u32::MAX),
9698
}
9799
}
98-
Err(MemoryError::OutOfFuel { required_fuel }) => {
100+
Err(StoreError::External(MemoryError::OutOfFuel { required_fuel })) => {
99101
return Err(Error::from(ResumableOutOfFuelError::new(required_fuel)))
100102
}
101-
Err(MemoryError::ResourceLimiterDeniedAllocation) => {
103+
Err(StoreError::External(MemoryError::ResourceLimiterDeniedAllocation)) => {
102104
return Err(Error::from(TrapCode::GrowthOperationLimited))
103105
}
104-
Err(error) => panic!("encountered an unexpected error: {error}"),
106+
Err(error) => {
107+
panic!("`table.grow`: internal interpreter error: {error}")
108+
}
105109
};
106110
self.set_stack_slot(result, return_value);
107111
self.try_next_instr_at(2)

crates/wasmi/src/engine/executor/instrs/table.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{
99
Op,
1010
Slot,
1111
},
12-
store::{PrunedStore, StoreInner},
12+
store::{PrunedStore, StoreError, StoreInner},
1313
Error,
1414
TrapCode,
1515
};
@@ -224,20 +224,24 @@ impl Executor<'_> {
224224
let value = self.get_stack_slot(value);
225225
let return_value = match store.grow_table(&table, delta, value) {
226226
Ok(return_value) => return_value,
227-
Err(TableError::GrowOutOfBounds | TableError::OutOfSystemMemory) => {
227+
Err(StoreError::External(
228+
TableError::GrowOutOfBounds | TableError::OutOfSystemMemory,
229+
)) => {
228230
let table_ty = store.inner().resolve_table(&table).ty();
229231
match table_ty.is_64() {
230232
true => u64::MAX,
231233
false => u64::from(u32::MAX),
232234
}
233235
}
234-
Err(TableError::OutOfFuel { required_fuel }) => {
236+
Err(StoreError::External(TableError::OutOfFuel { required_fuel })) => {
235237
return Err(Error::from(ResumableOutOfFuelError::new(required_fuel)))
236238
}
237-
Err(TableError::ResourceLimiterDeniedAllocation) => {
239+
Err(StoreError::External(TableError::ResourceLimiterDeniedAllocation)) => {
238240
return Err(Error::from(TrapCode::GrowthOperationLimited))
239241
}
240-
Err(error) => panic!("encountered unexpected error: {error}"),
242+
Err(error) => {
243+
panic!("`memory.grow`: internal interpreter error: {error}")
244+
}
241245
};
242246
self.set_stack_slot(result, return_value);
243247
self.try_next_instr_at(2)
@@ -246,7 +250,7 @@ impl Executor<'_> {
246250
/// Executes an [`Op::ElemDrop`].
247251
pub fn execute_element_drop(&mut self, store: &mut StoreInner, segment_index: Elem) {
248252
let segment = self.get_element_segment(segment_index);
249-
store.resolve_element_segment_mut(&segment).drop_items();
253+
store.resolve_element_mut(&segment).drop_items();
250254
self.next_instr();
251255
}
252256
}

crates/wasmi/src/global.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ impl Global {
5656
}
5757

5858
/// Returns the [`GlobalType`] of the global variable.
59+
///
60+
/// # Panics
61+
///
62+
/// Panics if `ctx` does not own this [`Global`].
5963
pub fn ty(&self, ctx: impl AsContext) -> GlobalType {
6064
ctx.as_context().store.inner.resolve_global(self).ty()
6165
}

crates/wasmi/src/reftype.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl ExternRef {
126126
///
127127
/// Panics if `ctx` does not own this [`ExternRef`].
128128
pub fn data<'a, T: 'a>(&self, ctx: impl Into<StoreContext<'a, T>>) -> &'a dyn Any {
129-
ctx.into().store.inner.resolve_external_object(self).data()
129+
ctx.into().store.inner.resolve_externref(self).data()
130130
}
131131
}
132132

crates/wasmi/src/store/error.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
use core::{any::type_name, fmt};
2+
3+
#[cfg(doc)]
4+
use super::{PrunedStore, Store, StoreInner};
5+
6+
/// An error occurred on [`Store<T>`] or [`StoreInner`] methods.
7+
#[derive(Debug, Copy, Clone)]
8+
pub enum StoreError<E> {
9+
/// An error representing an internal error, a.k.a. a bug or invalid behavior within Wasmi.
10+
Internal(InternalStoreError),
11+
/// An external error forwarded by the [`Store`] or [`StoreInner`].
12+
External(E),
13+
}
14+
15+
impl<E: fmt::Display> fmt::Display for StoreError<E> {
16+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17+
match self {
18+
StoreError::Internal(error) => fmt::Display::fmt(error, f),
19+
StoreError::External(error) => fmt::Display::fmt(error, f),
20+
}
21+
}
22+
}
23+
24+
/// A [`Store`] or [`StoreInner`] internal error, a.k.a. bug or invalid behavior within Wasmi.
25+
#[derive(Debug, Copy, Clone)]
26+
pub struct InternalStoreError {
27+
kind: InternalStoreErrorKind,
28+
}
29+
30+
impl InternalStoreError {
31+
/// Creates a new [`InternalStoreError`].
32+
fn new(kind: InternalStoreErrorKind) -> Self {
33+
Self { kind }
34+
}
35+
36+
/// An error indicating that a [`Store`] resource could not be found.
37+
#[cold]
38+
#[inline]
39+
pub fn not_found() -> Self {
40+
Self::new(InternalStoreErrorKind::EntityNotFound)
41+
}
42+
43+
/// An error indicating that a [`Store`] resource does not originate from the store.
44+
#[cold]
45+
#[inline]
46+
pub fn store_mismatch() -> Self {
47+
Self::new(InternalStoreErrorKind::StoreMismatch)
48+
}
49+
50+
/// An error indicating that restoring a [`PrunedStore`] to a [`Store<T>`] mismatched `T`.
51+
#[cold]
52+
#[inline]
53+
pub fn restore_type_mismatch<T>() -> Self {
54+
Self::new(InternalStoreErrorKind::RestoreTypeMismatch(
55+
RestoreTypeMismatchError::new::<T>(),
56+
))
57+
}
58+
}
59+
60+
impl fmt::Display for InternalStoreError {
61+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62+
let message = match &self.kind {
63+
InternalStoreErrorKind::RestoreTypeMismatch(error) => {
64+
return fmt::Display::fmt(error, f)
65+
}
66+
InternalStoreErrorKind::StoreMismatch => "store owner mismatch",
67+
InternalStoreErrorKind::EntityNotFound => "entity not found",
68+
};
69+
write!(f, "failed to resolve entity: {message}")
70+
}
71+
}
72+
73+
#[derive(Debug, Copy, Clone)]
74+
enum InternalStoreErrorKind {
75+
/// An error when restoring a [`PrunedStore`] with an incorrect `T` for [`Store<T>`].
76+
RestoreTypeMismatch(RestoreTypeMismatchError),
77+
/// An error indicating that a store resource does not originate from the given store.
78+
StoreMismatch,
79+
/// An error indicating that a store resource was not found.
80+
EntityNotFound,
81+
}
82+
83+
impl<E> StoreError<E> {
84+
/// Create a new [`StoreError`] from the external `error`.
85+
pub fn external(error: E) -> Self {
86+
Self::External(error)
87+
}
88+
}
89+
90+
impl<E> From<InternalStoreError> for StoreError<E> {
91+
fn from(error: InternalStoreError) -> Self {
92+
Self::Internal(error)
93+
}
94+
}
95+
96+
/// Error occurred when restoring a [`PrunedStore`] to a [`Store<T>`] with an mismatching `T`.
97+
#[derive(Debug, Copy, Clone)]
98+
struct RestoreTypeMismatchError {
99+
type_name: fn() -> &'static str,
100+
}
101+
102+
impl RestoreTypeMismatchError {
103+
/// Create a new [`RestoreTypeMismatchError`].
104+
pub fn new<T>() -> Self {
105+
Self {
106+
type_name: type_name::<T>,
107+
}
108+
}
109+
}
110+
111+
impl fmt::Display for RestoreTypeMismatchError {
112+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113+
write!(
114+
f,
115+
"failed to unprune store due to type mismatch: {}",
116+
(self.type_name)()
117+
)
118+
}
119+
}

0 commit comments

Comments
 (0)