Skip to content

Handle disposed AsyncWaitHandle during BeginInvoke completion - #14998

Merged
KlausLoeffelmann merged 1 commit into
dotnet:mainfrom
WiseTechGlobal:JWA/14996-disposed-async-wait-handle
Sep 7, 2026
Merged

Handle disposed AsyncWaitHandle during BeginInvoke completion#14998
KlausLoeffelmann merged 1 commit into
dotnet:mainfrom
WiseTechGlobal:JWA/14996-disposed-async-wait-handle

Conversation

@jaywang-cn

@jaywang-cn jaywang-cn commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • tolerate ObjectDisposedException when ThreadMethodEntry.Complete signals an AsyncWaitHandle disposed by its consumer
  • add a regression test that verifies the callback runs and the async result completes

Fixes #14996

Testing

  • dotnet test src/test/unit/System.Windows.Forms/System.Windows.Forms.Tests.csproj --no-restore -- --filter-method System.Windows.Forms.Tests.ControlTests.Control_BeginInvoke_DisposedAsyncWaitHandle_CompletesCallback (1 passed)
Microsoft Reviewers: Open in CodeFlow

@jaywang-cn
jaywang-cn requested a review from a team as a code owner August 28, 2026 08:23
@KlausLoeffelmann

Copy link
Copy Markdown
Member

Thanks for the excellent report and focused fix.
FWIW, the lifetime-analysis (WaitHandle) and picking up the runtime precedent was technically sharp, sound, helpful and made this straightforward to assess!

@KlausLoeffelmann KlausLoeffelmann 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 for your contribution!

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.

🟢 Approval recommended

Pull request overview

This PR hardens WinForms Control.BeginInvoke completion so that a consumer-disposed IAsyncResult.AsyncWaitHandle no longer causes an ObjectDisposedException on the UI thread during marshaled callback completion.

Changes:

  • Catch and tolerate ObjectDisposedException when ThreadMethodEntry.Complete() signals the internal ManualResetEvent.
  • Add a regression test ensuring the marshaled callback still runs and the returned IAsyncResult reports completion even if AsyncWaitHandle is disposed.
File summaries
File Description
src/System.Windows.Forms/System/Windows/Forms/Control.ThreadMethodEntry.cs Wraps completion signaling (_resetEvent?.Set()) in an ObjectDisposedException handler to prevent UI-thread crashes when the wait handle is externally disposed.
src/test/unit/System.Windows.Forms/System/Windows/Forms/ControlTests.Methods.cs Adds a regression test that disposes AsyncWaitHandle before invoking marshaled callbacks and verifies callback execution and IsCompleted.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

{
_resetEvent?.Set();
}
catch (ObjectDisposedException)

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.

Instead of catching an exception, can we check: if(!_marshaler.IsDisposed)

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.

No. We could have the waitHandle disposed ...

IAsyncResult result = control.BeginInvoke(callback);
result.AsyncWaitHandle.Dispose();

... but not the marshaling control.

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.

🟢 Approval recommended

The change matches the issue’s acceptance criteria and the added regression test validates the previously failing scenario.

Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

@KlausLoeffelmann

Copy link
Copy Markdown
Member

Merging this, as this is a bug fix of an existing feature, and not a contribution of a new feature.

@jaywang-cn - for contribution other than bug fixes, please take a look at the contributor licence agreement, which we would need to take respective PRs. Thanks for you help on this matter!

@KlausLoeffelmann
KlausLoeffelmann merged commit f0cd8e4 into dotnet:main Sep 7, 2026
9 of 10 checks passed
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.

Control.BeginInvoke completion throws ObjectDisposedException when AsyncWaitHandle is disposed

4 participants