Skip to content

Fix wasip3 blocking UDP subtask handle leaks - #868

Open
SebTardif wants to merge 6 commits into
WebAssembly:mainfrom
SebTardif:fix/wasip3-udp-subtask-drop
Open

Fix wasip3 blocking UDP subtask handle leaks#868
SebTardif wants to merge 6 commits into
WebAssembly:mainfrom
SebTardif:fix/wasip3-udp-subtask-drop

Conversation

@SebTardif

Copy link
Copy Markdown
Contributor

Summary

On wasip3, when a blocking UDP recv/send waits for a pending
component-model subtask and the wait completes, the handle must be
dropped. The nonblocking paths already do this. The blocking success
paths only cleared the field and leaked the handle.

  • recv: call wasip3_recv_end after a successful wait (same as the
    nonblocking path)
  • send: do not zero send_subtask before the shared
    wasip3_subtask_drop block so that drop actually runs
  • test: dual-process blocking UDP roundtrips (64 cycles); server
    blocks in recvfrom before each client send so a pending receive
    subtask is common

Timeout paths still leave the subtask in place for a later retry.

Origin

Introduced in #775 (2026-04-03) when nonblocking UDP I/O was added.

Related

On wasip3, blocking recv/send that wait for a pending subtask must drop
the component-model handle when the wait completes. The nonblocking
paths already did this; the blocking success paths only cleared the
handle field and leaked.

- recv: call wasip3_recv_end after a successful wait (drop + clear)
- send: do not zero send_subtask before the shared drop block
- Add dual-process blocking UDP roundtrip suite test (64 cycles)

@alexcrichton alexcrichton left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Locally I'm seeing the test pass both before and after this change -- would it be possible to write the test such that it fails beforehand and passes afterwards?

I/O-only roundtrips pass with or without subtask drop because the
payload is already in guest storage after wait. Cap wasmtime concurrent
resources (-Smax-resources=128) on the dual-process suite so undropped
HostTask entries fail with "resource table has no free keys" while a
correct drop stays under the cap. Raise rounds to 200 and timeout to 15s.
@SebTardif

Copy link
Copy Markdown
Contributor Author

Thanks for catching that, Alex. You are right: a pure send/recv correctness test cannot fail on this bug. After a successful blocking wait the datagram (or send completion) is already in guest-side storage, so clearing recv_subtask/send_subtask without wasip3_subtask_drop still returns the right bytes. The defect is only that the component-model subtask handle (wasmtime HostTask in the concurrent resource table) is never released.

I pushed a stronger red/green setup on the dual-process suite:

  • Keep the server-first multi-roundtrip traffic so the pending-subtask wait path is exercised.
  • On wasip3 only, run the pair under wasmtime -Smax-resources=128.
  • With the missing drop, undropped HostTask entries accumulate and wasmtime fails with resource table has no free keys.
  • With the fix, subtasks are dropped after each completion so the concurrent table stays under the cap.

Rounds are 200 and the harness timeout is 15s for that test. wasip2 is unchanged (no async subtasks on this path).

If 128 is too tight for baseline wasip3 CLI/socket bookkeeping on some runners, we can raise the cap slightly while keeping N large enough that a one-leak-per-completion path still trips it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants