Skip to content

AccessibleObject answers IRawElementProviderFragment.get_FragmentRoot with S_OK and a null root; UIAutomationCore crashes in TextPattern.RangeFromPoint and the app freezes 15-30 s under JAWS #15043

Description

@Menelion

.NET version

.NET 10.0.11 (System.Windows.Forms.dll from Microsoft.WindowsDesktop.App\10.0.11), Windows 11 Pro 26100 (build lab 26100.1.amd64fre.ge_release), UIAutomationCore.dll 7.2.26100.9278.

Did it work in .NET Framework?

Not tested. .NET Framework TextBox does not implement the UIA text provider in-process, so the code path does not exist there.

Did it work in any of the earlier releases of .NET Core or .NET 5+?

Not tested. The relevant code (AccessibleObject implementing IRawElementProviderFragment with FragmentRoot => null) is present on release/10.0; I have not bisected older releases.

Issue description

With the JAWS screen reader running and its Mouse Echo feature on, the first time the mouse pointer passes over a WinForms TextBox the whole application stops responding for 15–30 seconds. It happens once per process. Turning Mouse Echo off removes it. A Win32 application with a plain EDIT control does not reproduce.

A full process dump taken during the freeze (analyzed with cdb and public Microsoft symbols) shows the chain:

  1. JAWS calls TextPattern.RangeFromPoint on the text box under the pointer. It is a cross-process COM call into the application, dispatched on the UI thread via combase!ThreadWndProc.
  2. UIAutomationCore!RemotePatternStub::Text_RangeFromPointScreenPointToProviderPointHelperUiaUtils::TryGetCoordinateConverterForVisualRelativeRoot queries the element for IRawElementProviderFragment (succeeds) and calls get_FragmentRoot (returns S_OK).
  3. WinForms hands back S_OK with a null IRawElementProviderFragmentRoot*. AccessibleObject.FragmentRoot defaults to null, TextBoxBase.TextBoxBaseAccessibleObject does not override it, and IRawElementProviderFragment.Interface.get_FragmentRoot does *pRetVal = ComHelpers.TryGetComPointer<IRawElementProviderFragmentRoot>(FragmentRoot); return HRESULT.S_OK; (AccessibleObject.cs, release/10.0).
  4. UIAutomationCore dereferences the null root: mov rax,[rcx] with rcx = 0, EXCEPTION_ACCESS_VIOLATION at UIAutomationCore+0x1e9bb7.
  5. COM's server-side stub filter (combase!ServerExceptionFilter) swallows the exception and calls SilentlyReportExceptionsRtlReportExceptionntdll!WerpWaitForCrashReporting. The UI thread blocks there until Windows Error Reporting has written a minidump of the process. That wait is the visible freeze. COM reports only the first stub exception per process, hence once per launch.

UIAutomationCore should not dereference the null (separately reported to Windows), but the UIA contract for IRawElementProviderFragment::get_FragmentRoot is that a fragment returns its root, and WinForms exposes the fragment interface on every AccessibleObject while returning nothing from it.

Resolved UI-thread stack (newest first, abridged):

ntdll!NtWaitForMultipleObjects
ntdll!WerpWaitForCrashReporting
ntdll!RtlReportException
combase!SilentlyReportExceptions
combase!ServerExceptionFilter
combase!AppInvokeExceptionFilterWithMethodAddress
ntdll!KiUserExceptionDispatch
UIAutomationCore!UiaUtils::TryGetCoordinateConverterForVisualRelativeRoot+0x73   <- AV, rcx = 0
UIAutomationCore!`anonymous namespace'::ScreenPointToProviderPointHelper+0x7e
UIAutomationCore!RemotePatternStub::Text_RangeFromPoint+0xca
UIAutomationCore!InvokePatternMethodOnCorrectContext_Callback+0x26f
OneCoreCommonProxyStub!IServiceProvider_RemoteQueryService_Thunk+0x2f
rpcrt4!Ndr64StubWorker+0x862
combase!CStdStubBuffer_Invoke+0x7d
combase!ReentrantSTAInvokeInApartment+0x194
combase!ThreadDispatch+0x3ef
combase!ThreadWndProc+0x177
user32!DispatchMessageWorker+0x1dd
System.Windows.Forms.Application.LightThreadContext.FPushMessageLoop+0x160
System.Windows.Forms.Application.Run+0x6c

Disassembly at the fault, showing the successful get_FragmentRoot followed by the unchecked dereference:

call    UIAutomationCore!wil::try_com_query<IRawElementProviderFragment,IRawElementProviderSimple*&>
mov     rcx,qword ptr [rbp-28h]
test    rcx,rcx
je      +0xd4
and     qword ptr [rbp+38h],rdi          ; out param = null
lea     rdx,[rbp+38h]
call    UIAutomationCore!ProviderCallouts::get_FragmentRoot
mov     rcx,qword ptr [rbp+18h]
test    eax,eax
jns     +0x6a                            ; S_OK
and     qword ptr [rbp+28h],0
mov     rcx,qword ptr [rbp+38h]          ; rcx = 0
mov     rax,qword ptr [rcx]              ; <- access violation

Windows Event Log, Application: Application Error 1000 / Windows Error Reporting 1001, faulting module UIAutomationCore.DLL 7.2.26100.9278, exception code 0xc0000005, fault offset 0x1e9bb7, recorded for every launch that was touched by the mouse under JAWS.

Managed heap at the time of the dump contained System.Windows.Forms.TextBox+TextBoxAccessibleObject (×2) and System.Windows.Forms.TextBoxBase+TextBoxBaseUiaTextProvider (×2), matching the two text boxes on the form.

Steps to reproduce

  1. Windows 11, JAWS 2026 (tested with jhook.dll 27.5.20) running, Mouse Echo enabled (Settings Center → Mouse Echo).
  2. Create a WinForms app targeting net10.0-windows with a form containing one TextBox { Multiline = true, Dock = DockStyle.Fill } (a second control such as a ListBox is optional; a ListBox plus TextBox form reproduced identically).
  3. Run it and move the mouse pointer across the text box once.
  4. The window stops responding for 15–30 seconds, then recovers. Event Viewer → Application shows an Application Error 1000 for the app with faulting module UIAutomationCore.DLL, exception 0xc0000005, offset 0x1e9bb7. Subsequent mouse passes do not freeze (COM reports only the first exception per process), but a new process freezes again.

Expected: a UIA client calling TextPattern.RangeFromPoint on a WinForms text box gets a range or an error HRESULT; the application never blocks on WER.

The same call should be reachable without a screen reader by any UIA client invoking IUIAutomationTextPattern::RangeFromPoint against the text box's element; I have only verified it via JAWS.

A dump of the freeze from a data-free test application can be provided on request.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions