Skip to content

Fix CancelAsync wait handle disposal when no callbacks remain - #136752

Open
MihaZupan wants to merge 1 commit into
dotnet:mainfrom
MihaZupan:cancelasync-handle-disposal
Open

MihaZupan wants to merge 1 commit into
dotnet:mainfrom
MihaZupan:cancelasync-handle-disposal

Conversation

@MihaZupan

@MihaZupan MihaZupan commented Oct 31, 2026 •

Copy link
Copy Markdown
Member

CancelAsync() leaves the source in the notifying state when its no-callback fast path returns. A subsequent Dispose() therefore skips closing an existing wait handle because it treats cancellation as still in progress.

Mark cancellation complete on that fast path, using the existing volatile state field. This preserves the guard for concurrent cancellation and the immediate return of subsequent cancellation requests.

Regression coverage includes absent and unregistered callbacks, wait handles created before or after cancellation, and handle lifetime with an asynchronous callback.

Resolves #136748

Note

This pull request was prepared with GitHub Copilot.

Mark the no-callback fast path complete so disposing the cancellation source closes its wait handle. Cover absent and unregistered callbacks and handle lifetime during asynchronous cancellation.

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).
12 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @VSadov
See info in area-owners.md if you want to be subscribed.

This branch has not been deployed

No deployments
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.

CancellationTokenSource.CancelAsync leaves WaitHandle undisposed when no callbacks are registered

1 participant