Skip to content

Bug: uithread-dispatcher-exit-null-dispatcher-referenceequals #889

Description

@drmoisan
  • Work Mode: minor-audit

Summary

The dispatcher exit of SynchronizationContextAwaiter.IsCompleted in UtilitiesCS/Threading/UiThread.cs (lines 197-201 after the #816 hardening landed) carries the same null-reference-equals-null defect shape that #816 just fixed one exit above it: when the captured _dispatcher field is null and the executing thread also has no dispatcher, ReferenceEquals(Dispatcher.FromThread(Thread.CurrentThread), _dispatcher) compares null to null and evaluates true, so the accessor can return true for a thread that owns no UI dispatcher.

Environment

  • OS/version: Windows (TaskMaster repo host)
  • Python version: N/A (C#/.NET Framework repository)
  • Command/flags used: N/A (found during code review, not via a failing run)
  • Data source or fixture: UtilitiesCS/Threading/UiThread.cs, reviewed on branch bug/uithread-iscompleted-branch2-residual-and-ac5-apartment-measurement-816 at commit b4941e252 during the issue Bug: uithread-iscompleted-branch2-residual-and-ac5-apartment-measurement #816 feature review (feature-audit dated 2026-09-14T00-40)

Steps to Reproduce

  1. Call UiThread.Initialize() (or the equivalent capture path) such that it throws after the UI-thread-id field is assigned but before the _dispatcher field is assigned - i.e. between the UiThreadId assignment and the Dispatcher assignment in the initializer.
  2. This leaves _uiThreadId set to a real thread id and _dispatcher at its default value of null.
  3. From a thread whose managed thread id equals the captured _uiThreadId, but which owns no WPF dispatcher, await a DispatcherSynchronizationContext that belongs to a different thread than the one captured.
  4. Evaluate SynchronizationContextAwaiter.IsCompleted on that awaiter.

Expected Behavior

The dispatcher exit should return false when the captured _dispatcher is null, because a null captured dispatcher means no UI dispatcher was ever actually captured and the awaiter should not report completion as if the executing thread were dispatcher-verified.

Actual Behavior

return _context is DispatcherSynchronizationContext && ReferenceEquals(Dispatcher.FromThread(Thread.CurrentThread), _dispatcher); - when _dispatcher is null and Dispatcher.FromThread(Thread.CurrentThread) is also null (the executing thread owns no dispatcher), ReferenceEquals(null, null) is true, so the whole expression can evaluate true given a matching DispatcherSynchronizationContext-typed ambient context. This is the identical defect shape that issue #816 hardened one exit above (the _uiSyncContext exit), where the delivered fix's own comment states the added null-dispatcher guard is "load-bearing, not redundant" for exactly this reason.

Logs / Screenshots

  • Attached minimal logs or screenshot
  • Snippet:
// UtilitiesCS/Threading/UiThread.cs, current dispatcher exit (post-#816):
return _context is DispatcherSynchronizationContext
    && ReferenceEquals(
        System.Windows.Threading.Dispatcher.FromThread(Thread.CurrentThread),
        _dispatcher
    );

Impact / Severity

  • Blocker
  • High
  • Medium
  • Low

Source

From: docs/features/potential/2026-09-14-uithread-dispatcher-exit-null-dispatcher-referenceequals.md

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions