Skip to content

Commit b856261

Browse files
authored
refactor recursive reentrance checks (#12349)
* refactor recursive reentrance checks This commit makes a few changes related to recursive reentrance checks, instance poisoning, etc.: - Implements the more restrictive lift/lower rules described in WebAssembly/component-model#589 such that a component instance may not lower a function lifted by one of its ancestors, nor vice-versa. Any such lower will result in a fused adapter which traps unconditionally, preventing guest-to-guest recursive reentrance without requiring data flow analysis. - Note that this required updating several WAST tests which were violating the new rule, including some in the `tests/component-model` Git submodule, which I've updated. - This is handled entirely in the `fact` module now; I've removed the `AlwaysTrap` case previously handled by `wasmtime-cranelift`. - Removes `FLAG_MAY_ENTER` from `InstanceFlags`. It is no longer needed for guest-to-guest calls due to the above, and for guest-to-host-to-guest calls we can rely on either `FLAG_NEEDS_POST_RETURN` for sync-lifted functions or the `GuestTask` call stack for async-lifted functions. - Adds a `StoreOpaque::trapped` field which is set when _any_ instance belonging to that store traps, at which point the entire store is considered poisoned, meaning no instance belonging to it may be entered. This prevents indeterminant concurrent task state left over from the trapping instance from leaking into other instances. Note that this does _not_ include code to push and pop `GuestTask` instances for guest-to-guest sync-to-sync calls, nor for host-to-guest calls using e.g. the synchronous `Func::call` API, so certain intrinsics which expect a `GuestTask` to be present such as `backpressure.inc` will still fail in such cases. I'll address that in a later PR. Also note that I made a small change to `wasmtime-wit-bindgen`, adding a `Send` bound on the `T` type parameter for `store | async` functions. This allowed me to recursively call `{Typed}Func::call_concurrent` from inside a host function, and it doesn't have any downsides AFAICT. Fixes #12128 * bless bindgen expansions * bless disas tests * address review feedback * sync `trap.h` with `trap_encoding.rs` ...and add const assertions to `trap.rs` to help avoid future divergence.
1 parent 2e23e22 commit b856261

105 files changed

Lines changed: 1612 additions & 1239 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

crates/c-api/include/wasmtime/trap.h

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,6 @@ enum wasmtime_trap_code_enum {
4747
WASMTIME_TRAP_CODE_UNREACHABLE_CODE_REACHED,
4848
/// Execution has potentially run too long and may be interrupted.
4949
WASMTIME_TRAP_CODE_INTERRUPT,
50-
/// When the `component-model` feature is enabled this trap represents a
51-
/// function that was `canon lift`'d, then `canon lower`'d, then called.
52-
/// This combination of creation of a function in the component model
53-
/// generates a function that always traps and, when called, produces this
54-
/// flavor of trap.
55-
WASMTIME_TRAP_CODE_ALWAYS_TRAP_ADAPTER,
5650
/// Execution has run out of the configured fuel amount.
5751
WASMTIME_TRAP_CODE_OUT_OF_FUEL,
5852
/// Used to indicate that a trap was raised by atomic wait operations on non
@@ -74,9 +68,47 @@ enum wasmtime_trap_code_enum {
7468
/// Async-lifted export failed to produce a result by calling `task.return`
7569
/// before returning `STATUS_DONE` and/or after all host tasks completed.
7670
WASMTIME_TRAP_CODE_NO_ASYNC_RESULT,
71+
/// We are suspending to a tag for which there is no active handler.
72+
WASMTIME_TRAP_CODE_UNHANDLED_TAG,
73+
/// Attempt to resume a continuation twice.
74+
WASMTIME_TRAP_CODE_CONTINUATION_ALREADY_CONSUMED,
7775
/// A Pulley opcode was executed at runtime when the opcode was disabled at
7876
/// compile time.
7977
WASMTIME_TRAP_CODE_DISABLED_OPCODE,
78+
/// Async event loop deadlocked; i.e. it cannot make further progress given
79+
/// that all host tasks have completed and any/all host-owned stream/future
80+
/// handles have been dropped.
81+
WASMTIME_TRAP_CODE_ASYNC_DEADLOCK,
82+
/// When the `component-model` feature is enabled this trap represents a
83+
/// scenario where a component instance tried to call an import or intrinsic
84+
/// when it wasn't allowed to, e.g. from a post-return function.
85+
WASMTIME_TRAP_CODE_CANNOT_LEAVE_COMPONENT,
86+
/// A synchronous task attempted to make a potentially blocking call prior
87+
/// to returning.
88+
WASMTIME_TRAP_CODE_CANNOT_BLOCK_SYNC_TASK,
89+
/// A component tried to lift a `char` with an invalid bit pattern.
90+
WASMTIME_TRAP_CODE_INVALID_CHAR,
91+
/// Debug assertion generated for a fused adapter regarding the expected
92+
/// completion of a string encoding operation.
93+
WASMTIME_TRAP_CODE_DEBUG_ASSERT_STRING_ENCODING_FINISHED,
94+
/// Debug assertion generated for a fused adapter regarding a string
95+
/// encoding operation.
96+
WASMTIME_TRAP_CODE_DEBUG_ASSERT_EQUAL_CODE_UNITS,
97+
/// Debug assertion generated for a fused adapter regarding the alignment of
98+
/// a pointer.
99+
WASMTIME_TRAP_CODE_DEBUG_ASSERT_POINTER_ALIGNED,
100+
/// Debug assertion generated for a fused adapter regarding the upper bits
101+
/// of a 64-bit value.
102+
WASMTIME_TRAP_CODE_DEBUG_ASSERT_UPPER_BITS_UNSET,
103+
/// A component tried to lift or lower a string past the end of its memory.
104+
WASMTIME_TRAP_CODE_STRING_OUT_OF_BOUNDS,
105+
/// A component tried to lift or lower a list past the end of its memory.
106+
WASMTIME_TRAP_CODE_LIST_OUT_OF_BOUNDS,
107+
/// A component used an invalid discriminant when lowering a variant value.
108+
WASMTIME_TRAP_CODE_INVALID_DISCRIMINANT,
109+
/// A component passed an unaligned pointer when lifting or lowering a
110+
/// value.
111+
WASMTIME_TRAP_CODE_UNALIGNED_POINTER,
80112
};
81113

82114
/**

crates/c-api/src/trap.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,46 @@ use crate::{wasm_frame_vec_t, wasm_instance_t, wasm_name_t, wasm_store_t};
22
use std::cell::OnceCell;
33
use wasmtime::{Error, Trap, WasmBacktrace, format_err};
44

5+
// Help ensure the Rust enum matches the C one. If any of these assertions
6+
// fail, please update both this code and `trap.h` to sync them with
7+
// `trap_encoding.rs`.
8+
const _: () = {
9+
assert!(Trap::StackOverflow as u8 == 0);
10+
assert!(Trap::MemoryOutOfBounds as u8 == 1);
11+
assert!(Trap::HeapMisaligned as u8 == 2);
12+
assert!(Trap::TableOutOfBounds as u8 == 3);
13+
assert!(Trap::IndirectCallToNull as u8 == 4);
14+
assert!(Trap::BadSignature as u8 == 5);
15+
assert!(Trap::IntegerOverflow as u8 == 6);
16+
assert!(Trap::IntegerDivisionByZero as u8 == 7);
17+
assert!(Trap::BadConversionToInteger as u8 == 8);
18+
assert!(Trap::UnreachableCodeReached as u8 == 9);
19+
assert!(Trap::Interrupt as u8 == 10);
20+
assert!(Trap::OutOfFuel as u8 == 11);
21+
assert!(Trap::AtomicWaitNonSharedMemory as u8 == 12);
22+
assert!(Trap::NullReference as u8 == 13);
23+
assert!(Trap::ArrayOutOfBounds as u8 == 14);
24+
assert!(Trap::AllocationTooLarge as u8 == 15);
25+
assert!(Trap::CastFailure as u8 == 16);
26+
assert!(Trap::CannotEnterComponent as u8 == 17);
27+
assert!(Trap::NoAsyncResult as u8 == 18);
28+
assert!(Trap::UnhandledTag as u8 == 19);
29+
assert!(Trap::ContinuationAlreadyConsumed as u8 == 20);
30+
assert!(Trap::DisabledOpcode as u8 == 21);
31+
assert!(Trap::AsyncDeadlock as u8 == 22);
32+
assert!(Trap::CannotLeaveComponent as u8 == 23);
33+
assert!(Trap::CannotBlockSyncTask as u8 == 24);
34+
assert!(Trap::InvalidChar as u8 == 25);
35+
assert!(Trap::DebugAssertStringEncodingFinished as u8 == 26);
36+
assert!(Trap::DebugAssertEqualCodeUnits as u8 == 27);
37+
assert!(Trap::DebugAssertPointerAligned as u8 == 28);
38+
assert!(Trap::DebugAssertUpperBitsUnset as u8 == 29);
39+
assert!(Trap::StringOutOfBounds as u8 == 30);
40+
assert!(Trap::ListOutOfBounds as u8 == 31);
41+
assert!(Trap::InvalidDiscriminant as u8 == 32);
42+
assert!(Trap::UnalignedPointer as u8 == 33);
43+
};
44+
545
#[repr(C)]
646
pub struct wasm_trap_t {
747
pub(crate) error: Error,

crates/c-api/tests/trap.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ TEST(Trap, Codes) {
6060
TEST_CODE(BAD_CONVERSION_TO_INTEGER);
6161
TEST_CODE(UNREACHABLE_CODE_REACHED);
6262
TEST_CODE(INTERRUPT);
63-
TEST_CODE(ALWAYS_TRAP_ADAPTER);
6463
TEST_CODE(OUT_OF_FUEL);
6564
TEST_CODE(ATOMIC_WAIT_NON_SHARED_MEMORY);
6665
TEST_CODE(NULL_REFERENCE);

crates/component-macro/tests/expanded/char_concurrent.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,12 +191,12 @@ pub mod foo {
191191
use wasmtime::component::__internal::Box;
192192
pub trait HostWithStore: wasmtime::component::HasData + Send {
193193
/// A function that accepts a character
194-
fn take_char<T>(
194+
fn take_char<T: Send>(
195195
accessor: &wasmtime::component::Accessor<T, Self>,
196196
x: char,
197197
) -> impl ::core::future::Future<Output = ()> + Send;
198198
/// A function that returns a character
199-
fn return_char<T>(
199+
fn return_char<T: Send>(
200200
accessor: &wasmtime::component::Accessor<T, Self>,
201201
) -> impl ::core::future::Future<Output = char> + Send;
202202
}

crates/component-macro/tests/expanded/conventions_concurrent.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -224,47 +224,47 @@ pub mod foo {
224224
);
225225
};
226226
pub trait HostWithStore: wasmtime::component::HasData + Send {
227-
fn kebab_case<T>(
227+
fn kebab_case<T: Send>(
228228
accessor: &wasmtime::component::Accessor<T, Self>,
229229
) -> impl ::core::future::Future<Output = ()> + Send;
230-
fn foo<T>(
230+
fn foo<T: Send>(
231231
accessor: &wasmtime::component::Accessor<T, Self>,
232232
x: LudicrousSpeed,
233233
) -> impl ::core::future::Future<Output = ()> + Send;
234-
fn function_with_dashes<T>(
234+
fn function_with_dashes<T: Send>(
235235
accessor: &wasmtime::component::Accessor<T, Self>,
236236
) -> impl ::core::future::Future<Output = ()> + Send;
237-
fn function_with_no_weird_characters<T>(
237+
fn function_with_no_weird_characters<T: Send>(
238238
accessor: &wasmtime::component::Accessor<T, Self>,
239239
) -> impl ::core::future::Future<Output = ()> + Send;
240-
fn apple<T>(
240+
fn apple<T: Send>(
241241
accessor: &wasmtime::component::Accessor<T, Self>,
242242
) -> impl ::core::future::Future<Output = ()> + Send;
243-
fn apple_pear<T>(
243+
fn apple_pear<T: Send>(
244244
accessor: &wasmtime::component::Accessor<T, Self>,
245245
) -> impl ::core::future::Future<Output = ()> + Send;
246-
fn apple_pear_grape<T>(
246+
fn apple_pear_grape<T: Send>(
247247
accessor: &wasmtime::component::Accessor<T, Self>,
248248
) -> impl ::core::future::Future<Output = ()> + Send;
249-
fn a0<T>(
249+
fn a0<T: Send>(
250250
accessor: &wasmtime::component::Accessor<T, Self>,
251251
) -> impl ::core::future::Future<Output = ()> + Send;
252252
/// Comment out identifiers that collide when mapped to snake_case, for now; see
253253
/// https://github.com/WebAssembly/component-model/issues/118
254254
/// APPLE: func()
255255
/// APPLE-pear-GRAPE: func()
256256
/// apple-PEAR-grape: func()
257-
fn is_xml<T>(
257+
fn is_xml<T: Send>(
258258
accessor: &wasmtime::component::Accessor<T, Self>,
259259
) -> impl ::core::future::Future<Output = ()> + Send;
260-
fn explicit<T>(
260+
fn explicit<T: Send>(
261261
accessor: &wasmtime::component::Accessor<T, Self>,
262262
) -> impl ::core::future::Future<Output = ()> + Send;
263-
fn explicit_kebab<T>(
263+
fn explicit_kebab<T: Send>(
264264
accessor: &wasmtime::component::Accessor<T, Self>,
265265
) -> impl ::core::future::Future<Output = ()> + Send;
266266
/// Identifiers with the same name as keywords are quoted.
267-
fn bool<T>(
267+
fn bool<T: Send>(
268268
accessor: &wasmtime::component::Accessor<T, Self>,
269269
) -> impl ::core::future::Future<Output = ()> + Send;
270270
}

crates/component-macro/tests/expanded/dead-code_concurrent.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ pub mod a {
206206
);
207207
};
208208
pub trait HostWithStore: wasmtime::component::HasData + Send {
209-
fn f<T>(
209+
fn f<T: Send>(
210210
accessor: &wasmtime::component::Accessor<T, Self>,
211211
) -> impl ::core::future::Future<Output = LiveType> + Send;
212212
}

crates/component-macro/tests/expanded/direct-import_concurrent.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ pub struct FooIndices {}
9999
/// [`Linker`]: wasmtime::component::Linker
100100
pub struct Foo {}
101101
pub trait FooImportsWithStore: wasmtime::component::HasData + Send {
102-
fn foo<T>(
102+
fn foo<T: Send>(
103103
accessor: &wasmtime::component::Accessor<T, Self>,
104104
) -> impl ::core::future::Future<Output = ()> + Send;
105105
}

crates/component-macro/tests/expanded/flags_concurrent.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -304,31 +304,31 @@ pub mod foo {
304304
assert!(4 == < Flag64 as wasmtime::component::ComponentType >::ALIGN32);
305305
};
306306
pub trait HostWithStore: wasmtime::component::HasData + Send {
307-
fn roundtrip_flag1<T>(
307+
fn roundtrip_flag1<T: Send>(
308308
accessor: &wasmtime::component::Accessor<T, Self>,
309309
x: Flag1,
310310
) -> impl ::core::future::Future<Output = Flag1> + Send;
311-
fn roundtrip_flag2<T>(
311+
fn roundtrip_flag2<T: Send>(
312312
accessor: &wasmtime::component::Accessor<T, Self>,
313313
x: Flag2,
314314
) -> impl ::core::future::Future<Output = Flag2> + Send;
315-
fn roundtrip_flag4<T>(
315+
fn roundtrip_flag4<T: Send>(
316316
accessor: &wasmtime::component::Accessor<T, Self>,
317317
x: Flag4,
318318
) -> impl ::core::future::Future<Output = Flag4> + Send;
319-
fn roundtrip_flag8<T>(
319+
fn roundtrip_flag8<T: Send>(
320320
accessor: &wasmtime::component::Accessor<T, Self>,
321321
x: Flag8,
322322
) -> impl ::core::future::Future<Output = Flag8> + Send;
323-
fn roundtrip_flag16<T>(
323+
fn roundtrip_flag16<T: Send>(
324324
accessor: &wasmtime::component::Accessor<T, Self>,
325325
x: Flag16,
326326
) -> impl ::core::future::Future<Output = Flag16> + Send;
327-
fn roundtrip_flag32<T>(
327+
fn roundtrip_flag32<T: Send>(
328328
accessor: &wasmtime::component::Accessor<T, Self>,
329329
x: Flag32,
330330
) -> impl ::core::future::Future<Output = Flag32> + Send;
331-
fn roundtrip_flag64<T>(
331+
fn roundtrip_flag64<T: Send>(
332332
accessor: &wasmtime::component::Accessor<T, Self>,
333333
x: Flag64,
334334
) -> impl ::core::future::Future<Output = Flag64> + Send;

crates/component-macro/tests/expanded/floats_concurrent.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,18 +192,18 @@ pub mod foo {
192192
#[allow(unused_imports)]
193193
use wasmtime::component::__internal::Box;
194194
pub trait HostWithStore: wasmtime::component::HasData + Send {
195-
fn f32_param<T>(
195+
fn f32_param<T: Send>(
196196
accessor: &wasmtime::component::Accessor<T, Self>,
197197
x: f32,
198198
) -> impl ::core::future::Future<Output = ()> + Send;
199-
fn f64_param<T>(
199+
fn f64_param<T: Send>(
200200
accessor: &wasmtime::component::Accessor<T, Self>,
201201
x: f64,
202202
) -> impl ::core::future::Future<Output = ()> + Send;
203-
fn f32_result<T>(
203+
fn f32_result<T: Send>(
204204
accessor: &wasmtime::component::Accessor<T, Self>,
205205
) -> impl ::core::future::Future<Output = f32> + Send;
206-
fn f64_result<T>(
206+
fn f64_result<T: Send>(
207207
accessor: &wasmtime::component::Accessor<T, Self>,
208208
) -> impl ::core::future::Future<Output = f64> + Send;
209209
}

crates/component-macro/tests/expanded/host-world_concurrent.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ pub struct Host_Indices {}
9999
/// [`Linker`]: wasmtime::component::Linker
100100
pub struct Host_ {}
101101
pub trait Host_ImportsWithStore: wasmtime::component::HasData + Send {
102-
fn foo<T>(
102+
fn foo<T: Send>(
103103
accessor: &wasmtime::component::Accessor<T, Self>,
104104
) -> impl ::core::future::Future<Output = ()> + Send;
105105
}

0 commit comments

Comments
 (0)