Skip to content

[QUIC] Fix receive race. - #132287

Merged
rzikm merged 1 commit into
dotnet:mainfrom
ManickaP:quic-test-failure
Aug 14, 2026
Merged

[QUIC] Fix receive race.#132287
rzikm merged 1 commit into
dotnet:mainfrom
ManickaP:quic-test-failure

Conversation

@ManickaP

Copy link
Copy Markdown
Member

There's a race condition between HandleEventReceive and ReadAsync unblocking _receiveTcs twice.

  • HandleEventReceive will write data to the _receiveBuffers
  • ReadAsync will read them and unblock _receiveTcs and return to the caller
  • Another ReadAsync (with 0-byte read) will not copy anything and should wait for data
  • But now the second part of the initial HandleEventReceive happens and unblocks the _receiveTcs for the data that were already returned to the user in the first ReadAsync
  • Now the ReadAsync unblocks and returns and the caller interprets that we've received FIN and disposes the stream in good faith that the reading side is done, but it actually aborts instead

Fixes #121567, #109121

This was tested locally with sleep in HandleEventReceive that previously 100% reproduced the issue.

@ManickaP
ManickaP requested review from a team and a lite review from Copilot August 13, 2026 18:12
@ManickaP

Copy link
Copy Markdown
Member Author

/azp list

@azure-pipelines

Copy link
Copy Markdown
CI/CD Pipelines for this repository:

@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.

@ManickaP

Copy link
Copy Markdown
Member Author

/azp run runtime-libraries stress-http

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adjusts QuicStream.ReadAsync’s receive loop to be resilient to “stale” _receiveTcs wake-ups (i.e., a wake-up that occurs after buffered data was already consumed), preventing ReadAsync from returning 0 when no FIN has been received and avoiding premature stream disposal/abort scenarios.

Changes:

  • Updates the ReadAsync loop condition to keep waiting when no bytes were copied and the internal receive buffer is empty, filtering out stale _receiveTcs completions.
  • Threads through the “receive buffer empty” state from ReceiveBuffers.CopyTo(...) to drive the new waiting behavior.
  • Updates the loop’s explanatory comments to match the new behavior.

Comment thread src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs
@ManickaP

Copy link
Copy Markdown
Member Author

/ba-g failure is some pipeline error with publishing assets, unrelated

@rzikm rzikm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, Thanks!

@rzikm
rzikm merged commit 3221eac into dotnet:main Aug 14, 2026
81 of 83 checks passed
@ManickaP
ManickaP deleted the quic-test-failure branch August 14, 2026 08:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Test failure: System.Net.Quic.Tests.QuicStreamTests.MultipleReadsAndWrites

3 participants