From 7014480409bd04fa3d0e2572d15314d62d731a37 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 30 Jun 2026 01:54:52 +0000 Subject: [PATCH] [ci-fix] De-flake DispatcherTests pooled-thread state leak BackgroundThreadDoesNotGetDispatcherFromMainThread sets the [ThreadStatic] DispatcherProviderStubOptions.SkipDispatcherCreation flag inside a Task.Run delegate that executes on a ThreadPool thread, and never resets it. The pooled thread is returned to the pool with the flag still true. A later test whose async continuation resumes on that same pooled thread then gets a null dispatcher from Dispatcher.GetForCurrentThread(), producing an intermittent NullReferenceException (observed as green-on-retry flakiness). Reset the flag in a finally so the pooled thread is always returned clean. The Assert.Null assertion is preserved unchanged. Refs: dotnet/maui#36192 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../UnitTests/Dispatching/DispatcherTests.cs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Core/tests/UnitTests/Dispatching/DispatcherTests.cs b/src/Core/tests/UnitTests/Dispatching/DispatcherTests.cs index 586c962e04f5..6521366e99a4 100644 --- a/src/Core/tests/UnitTests/Dispatching/DispatcherTests.cs +++ b/src/Core/tests/UnitTests/Dispatching/DispatcherTests.cs @@ -60,10 +60,22 @@ public Task BackgroundThreadDoesNotGetDispatcherFromMainThread() => await Task.Run(() => { - DispatcherProviderStubOptions.SkipDispatcherCreation = true; - - var dispatcher = Dispatcher.GetForCurrentThread(); - Assert.Null(dispatcher); + // SkipDispatcherCreation is [ThreadStatic] and this delegate runs on a pooled + // thread. Reset it in a finally so the thread is returned to the pool clean. + // Otherwise the leaked flag makes Dispatcher.GetForCurrentThread() return null + // for a later test whose async continuation happens to resume on this same + // pooled thread, producing an intermittent NullReferenceException. + try + { + DispatcherProviderStubOptions.SkipDispatcherCreation = true; + + var dispatcher = Dispatcher.GetForCurrentThread(); + Assert.Null(dispatcher); + } + finally + { + DispatcherProviderStubOptions.SkipDispatcherCreation = false; + } }); });