Skip to content

[release/11.0] Fix ConcurrentQueue.TryDequeue spuriously reporting empty during a segment freeze - #132863

Open
github-actions[bot] wants to merge 1 commit into
release/11.0from
backport/pr-132737-to-release/11.0
Open

[release/11.0] Fix ConcurrentQueue.TryDequeue spuriously reporting empty during a segment freeze#132863
github-actions[bot] wants to merge 1 commit into
release/11.0from
backport/pr-132737-to-release/11.0

Conversation

@github-actions

@github-actions github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Backport of #132737 to release/11.0

/cc @VSadov @kafka1991

Customer Impact

  • Customer reported
  • Found internally

#132736

A race in ConcurrentQueue may result in TryDequeue/TryPeek assume the queue is empty when it actually has items.
The race is rare because it can happen only when the circular segment is completely full and the queue allocates a larger segment, while marking the old one "frozen" for more enqueues.

Regression

  • Yes
  • No

Testing

A new test is included together with the fix.

Risk

Low.

The fix changes the order of publishing _frozenForEnqueues with respect to updating segment Tail position to ensure that the consuming side does not see the segment in inconsistent state.

…gment freeze (#132737)

Fixes #132736

`ConcurrentQueueSegment.EnsureFrozenForEnqueues` published
`_frozenForEnqueues = true` before bumping the Tail by `FreezeOffset`,
while `TryDequeue`'s empty check reads the flag first and the Tail
second. In the window between the two stores a dequeuer can pair `frozen
== true` with the pre-freeze Tail and subtract `FreezeOffset` from a
Tail that was never bumped. A segment holds fewer than `FreezeOffset`
items, so `currentTail - FreezeOffset - currentHead <= 0` is then always
true and `TryDequeue` reports the segment empty while it still holds
committed items — a `false` return with no moment during the call at
which the queue was empty. The `Interlocked.Add` full fence does not
close the window; it only guarantees the stores become visible in
exactly this order, and the freezing thread can stall between them (see
the issue for the full interleaving and a reproducer that hits ~100
false-empties per 128M operations per round on current bits).

The fix bumps the Tail before publishing the flag. The reader's three
possible pairings become:

1. `frozen == true` — the bump is necessarily visible, so the Tail read
afterwards includes `FreezeOffset` and the frozen clause reports empty
only when the segment is genuinely drained.
2. `frozen == false` with a bumped Tail (freeze landed between the two
reads) — `currentTail - currentHead` is a large positive value, so the
check reports "not empty", spins, and retries; the next iteration takes
pairing 1. This is the bounded benign retry the existing comment in
`TryDequeue` already describes.
3. `frozen == false` with an un-bumped Tail — pre-freeze fast path,
unchanged.

Enqueuers never read the flag (a bumped Tail fails their sequence check
and routes them to `EnqueueSlow`, unchanged), and
`EnsureFrozenForEnqueues` only runs under the cross-segment lock, so the
`if (!_frozenForEnqueues)` guard is unaffected by the reordering.
@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.

@VSadov VSadov added this to the 11.0.0 milestone Aug 27, 2026
@VSadov VSadov added the Servicing-consider Issue for next servicing release review label Aug 27, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

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

Labels

area-System.Collections Servicing-consider Issue for next servicing release review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants