From 4cd8745efabb724770b007cfbf0fcbd63ac58020 Mon Sep 17 00:00:00 2001 From: GodlyDonuts Date: Mon, 22 Jun 2026 14:49:44 -0400 Subject: [PATCH] async: remove inter-task wakeup stream from its waitable set before cancelling `cancel_inter_task_stream_read` issued a synchronous `stream.cancel-read` on the inter-task wakeup stream while that stream was still a member of the task's waitable set, only calling `remove_waitable` afterwards. Per the Component Model (component-model#647), a synchronous `{stream,future}.cancel-{read,write}` traps if the waitable is still in a waitable set, for the same reason synchronous reads/writes do. Runtimes that enforce this trap (e.g. recent Wasmtime) therefore fault here during ordinary async operation. Reorder so the stream leaves the waitable set before the synchronous cancel, matching the unregister-then-cancel ordering already used by the general `WaitableOperation::cancel` path. The cancel result is discarded as before, so behavior is otherwise unchanged. --- crates/guest-rust/src/rt/async_support/inter_task_wakeup.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/guest-rust/src/rt/async_support/inter_task_wakeup.rs b/crates/guest-rust/src/rt/async_support/inter_task_wakeup.rs index d36d34bd6..31a84ea15 100644 --- a/crates/guest-rust/src/rt/async_support/inter_task_wakeup.rs +++ b/crates/guest-rust/src/rt/async_support/inter_task_wakeup.rs @@ -57,13 +57,17 @@ impl FutureState<'_> { } self.inter_task_wakeup.stream_reading = false; let handle = self.inter_task_wakeup.stream.as_mut().unwrap().handle(); + // Remove the stream from our waitable set before cancelling. A + // synchronous `stream.cancel-read` traps if the stream is still a member + // of a waitable set, so this must happen first. This matches the + // unregister-then-cancel ordering in `WaitableOperation::cancel`. + self.remove_waitable(handle); // Note that the return code here is discarded. No matter what the read // is cancelled, and whether we actually read something or whether we // cancelled doesn't matter. unsafe { UnitStreamOps.cancel_read(handle); } - self.remove_waitable(handle); } }