Summary
A host can transfer a Stream/Future readable handle while a host read is outstanding. The receiver gets a fresh readable endpoint while the old read buffer remains installed. A subsequent guest read attempts to rendezvous with another read.
Priority: high. Reproduced with real receiving Wasm on fd4266b516632e80943456a45aa64b95ea42f36f, Deno 2.9.5 / V8 15.0, Linux aarch64.
Reproduction and observed result
Create a stream, round-trip it through a guest pass-through export, then:
const pending = liftedStream.read(1);
await exports.readStream(liftedStream); // takes stream<u8>, invokes canon stream.read
Do not supply any writer data. The transfer succeeds, but the receiving canonical read raises internal AssertionError: int store. The instance is poisoned and a later independent ping export is refused. The original host stream read resolves with [0] even though no writer supplied data.
The future variant also reaches AssertionError: int store and poisons the instance; its parked host await rejects with PeerTrappedError.
Real-Wasm fixtures and type-checked probes are preserved locally in /tmp/opencode/stream-review/busy-read.wat and repro_test.ts. Lower-level host-buffer probes additionally demonstrate read-against-read rendezvous; the reported guest behavior above comes from actual compiled Wasm, not those substitutes.
Cause and authority
- streams.ts:227–236: Stream transfer checks prior consumption, not an outstanding read.
- streams.ts:594–623: Future has the same issue; awaiting host materialization introduces an additional initiation window.
contracts/embedder-api.md:474–489,513–516 defines readable ownership transfer and one in-flight operation per end/direction.
- The reference
lift_async_value checks IDLE on guest-to-host transfer. Its lower_stream / lower_future helpers create fresh readable endpoints without that check; this finding does not claim otherwise. The facade must maintain its host-end exclusion invariant.
Acceptance criteria
- Refuse transfer while a read is outstanding, before destructive transfer or guest entry can corrupt shared state.
- Cover Stream read, direct read, and Future reads, including operation initiation before host-materialization continuations run.
- Preserve the pending operation after refusal and keep the instance usable.
- Review already-consumed Future payloads so a fresh endpoint cannot read a single-use payload again.
- Retain real-Wasm regression coverage; run
just gates for the repair.
Summary
A host can transfer a Stream/Future readable handle while a host read is outstanding. The receiver gets a fresh readable endpoint while the old read buffer remains installed. A subsequent guest read attempts to rendezvous with another read.
Priority: high. Reproduced with real receiving Wasm on
fd4266b516632e80943456a45aa64b95ea42f36f, Deno 2.9.5 / V8 15.0, Linux aarch64.Reproduction and observed result
Create a stream, round-trip it through a guest pass-through export, then:
Do not supply any writer data. The transfer succeeds, but the receiving canonical read raises internal
AssertionError: int store. The instance is poisoned and a later independentpingexport is refused. The original host stream read resolves with[0]even though no writer supplied data.The future variant also reaches
AssertionError: int storeand poisons the instance; its parked host await rejects withPeerTrappedError.Real-Wasm fixtures and type-checked probes are preserved locally in
/tmp/opencode/stream-review/busy-read.watandrepro_test.ts. Lower-level host-buffer probes additionally demonstrate read-against-read rendezvous; the reported guest behavior above comes from actual compiled Wasm, not those substitutes.Cause and authority
contracts/embedder-api.md:474–489,513–516defines readable ownership transfer and one in-flight operation per end/direction.lift_async_valuechecks IDLE on guest-to-host transfer. Itslower_stream/lower_futurehelpers create fresh readable endpoints without that check; this finding does not claim otherwise. The facade must maintain its host-end exclusion invariant.Acceptance criteria
just gatesfor the repair.