Skip to content

[wasi] Support zero-byte socket receives - #136394

Merged
lewing merged 2 commits into
dotnet:mainfrom
lewing:lewing-wasi-zero-byte-receive
Oct 26, 2026
Merged

lewing merged 2 commits into
dotnet:mainfrom
lewing:lewing-wasi-zero-byte-receive

Conversation

@lewing

@lewing lewing commented Oct 23, 2026

Copy link
Copy Markdown
Member

On Unix, a zero-byte receive is implemented as a 1-byte MSG_PEEK. wasi-libc rejects MSG_PEEK with EOPNOTSUPP, so every zero-byte receive fails on WASI. Callers such as HTTP/2 in SocketsHttpHandler rely on zero-byte reads to wait for data.

This was split out of #136234 at a reviewer's request.

Fix

On WASI, a zero-byte receive with no flags now does this instead:

  • It polls the socket for POLLIN with a zero timeout, and completes only when the socket is readable.
  • If the socket can't be polled, it does a zero-length recv so the real error is reported. For example, wasi-libc returns EOPNOTSUPP for an unconnected TCP socket, and the recv reports ENOTCONN instead.
  • WASI poll events don't say which direction is ready, so queued zero-byte receives re-run this check. They no longer complete on any event.

Non-WASI behavior is unchanged.

Not covered: a zero-byte ReceiveFrom/ReceiveMessageFrom that passes an endpoint still takes the MSG_PEEK path on WASI.

Known caveat

After data has been drained, one zero-byte receive can complete early, because wasmtime keeps readiness set until a read would block. wasmtime treats this as by design (bytecodealliance/wasmtime#9667). The next real read then waits correctly.

Validation

  • CoreCLR WASI, Release, wasmtime 49.0.1: the full System.Net.Sockets functional tests ran 653 tests: 565 passed, 0 failed, 88 skipped. The baseline on main is about 645 run with 0 failed. The two new tests passed in all 4 variants that run on WASI.
  • macOS, Release: I ran the SendReceive_* classes (Sync, SyncForceNonBlocking, Apm, Task, Eap, SpanSync, MemoryArrayTask, MemoryNativeTask). Total was 252 with 0 failed, and both new tests passed in every variant.
  • Receive0Byte_NotConnected_Throws runs on all platforms. Receive0Byte_Udp_CompletesWhenDatagramArrives runs on Unix only, because on Windows a zero-byte receive consumes the datagram.
  • SocketsHttpHandler/HTTP/2 isn't enabled on WASI in main, so the motivating HTTP/2 scenario is covered in [wasi] Enable SocketsHttpHandler and WebSockets #136234 rather than here.
  • Building main locally needed the fgopt.cpp fix from Fix build break #136388. That fix is not part of this PR.

Related: #107981

Note

This PR was generated with GitHub Copilot.

lewing and others added 2 commits October 23, 2026 17:27
Unix implements a zero-byte receive as a 1-byte MSG_PEEK, which wasi-libc
rejects with EOPNOTSUPP, so zero-byte receives failed on WASI. On WASI, poll
the socket for input with a zero timeout instead. If the socket can't be
polled (for example an unconnected TCP socket), issue a zero-length recv so the
real error (ENOTCONN) is reported. Queued zero-byte receives re-run this check
rather than completing on any poll event.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@lewing
lewing marked this pull request as ready for review October 23, 2026 22:44
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @karelz, @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

@lewing lewing added arch-wasm WebAssembly architecture os-wasi Related to WASI variant of arch-wasm labels Oct 23, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.

@pavelsavara
pavelsavara requested review from rzikm and wfurt October 26, 2026 08:20
@lewing
lewing merged commit 8607e95 into dotnet:main Oct 26, 2026
106 checks passed
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 12.0-preview1 milestone Oct 27, 2026
@lewing
lewing deleted the lewing-wasi-zero-byte-receive branch October 28, 2026 03:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-wasm WebAssembly architecture area-System.Net.Sockets os-wasi Related to WASI variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants