Skip to content

bug: tab drag over terminal content can fail-fast in XAML due to DataView COM reentrancy under UI load #20512

Description

Windows Terminal version

Reproduced on both:

  • 1.24.11321.0 (WindowsTerminal.exe file version 1.24.2605.12001)
  • 1.24.11911.0 (WindowsTerminal.exe file version 1.24.2607.10001)

The latter is the current stable release installed from the Microsoft Store.

Windows build number

Windows 10 Pro x64, 10.0.19045, with Windows.UI.Xaml.dll version 10.0.19041.6456.

Other software

No third-party shell integration or privilege-management product has been identified in the crashing path. The foreground shell happens to be cmd.exe, but the faulting process is WindowsTerminal.exe, not cmd.exe.

Steps to reproduce

This is timing-dependent, but it has now occurred three times on the same machine:

  1. Open a Windows Terminal window with multiple active tabs.
  2. Produce sustained, high-volume output so that the terminal is actively rendering and has substantial scrollback.
  3. Begin dragging a tab.
  4. Move the dragged tab over the terminal content area, particularly while the UI is under load or while moving toward another window/tab strip.
  5. Windows Terminal may terminate immediately, taking every tab in that window/process with it.

The crash happens during DragOver; dropping the tab is not required. Lower UI load makes the issue much less frequent.

Expected behavior

Dragging/reordering/tearing out a tab must not terminate Windows Terminal. An internal tab drag that passes over terminal content should not be treated as an external file/text drop.

Actual behavior

The whole WindowsTerminal.exe process exits without a user-facing error. All tabs hosted by that process disappear.

Three observed incidents have the same Event Viewer signature:

Local time Terminal package App version Process uptime Dump/evidence
2026-07-10 18:07 1.24.11321.0 1.24.2605.12001 4h 38m Symbolized dump analysis retained
2026-08-05 10:27 1.24.11911.0 1.24.2607.10001 ~55m 806 MB full user dump
2026-08-05 15:05 1.24.11911.0 1.24.2607.10001 4h 38m 852 MB full user dump

Common Event 1000 signature:

Faulting application name: WindowsTerminal.exe
Faulting module name: Windows.UI.Xaml.dll, version: 10.0.19041.6456
Exception code: 0xc000027b
Fault offset: 0x0000000000481782

Representative WinDbg analysis:

PROCESS_NAME:  WindowsTerminal.exe
ERROR_CODE:    0xc000027b - An application-internal exception has occurred.
FAILURE_BUCKET_ID:
  STOWED_EXCEPTION_c000027b_Windows.UI.Xaml.dll!
  CXcpDispatcher::OnReentrancyProtectedWindowMessage
IMAGE_NAME:    Windows.UI.Xaml.dll
IMAGE_VERSION: 10.0.19041.6456

The fail-fast HRESULT passed to RaiseFailFastException is 0x8000ffff
(E_UNEXPECTED / Catastrophic failure).

The dump analysis showed peak commit in the approximately 594-630 MB range. There is no out-of-memory exception and no renderer/AtlasEngine frame in the failing path.

Full symbolized failing-thread stack

This is the representative fully symbolized stack from the same recurring 0xc000027b, Windows.UI.Xaml.dll+0x481782 signature. It captures the entire nested call from the fail-fast down through TermControl::_DragOverHandler, the XAML drag-over event, and the outer COM drag operation:

ntdll!RtlRaiseNoncontinuableException
KERNELBASE!RaiseFailFastException
combase!RoFailFastWithErrorContextInternal2
Windows_UI_Xaml!CXcpDispatcher::OnReentrancyProtectedWindowMessage
Windows_UI_Xaml!CXcpDispatcher::ProcessMessage [inline]
Windows_UI_Xaml!CXcpDispatcher::WindowProc
Windows_UI_Xaml!CDeferredInvoke::DispatchQueuedMessage
Windows_UI_Xaml!CXcpDispatcher::MessageTimerCallback [inline]
Windows_UI_Xaml!CXcpDispatcher::MessageTimerCallbackStatic
CoreMessaging!Microsoft__CoreUI__Dispatch__TimeoutHandler$CallbackThunk
CoreMessaging!Microsoft::CoreUI::Dispatch::TimeoutManager::Callback_OnDispatch
CoreMessaging!Microsoft::CoreUI::Dispatch::EventLoop::Callback_RunCoreLoop
CoreMessaging!Microsoft::CoreUI::Dispatch::UserAdapter::OnUserDispatch
CoreMessaging!Microsoft::CoreUI::Dispatch::UserAdapter_DoWork
CoreMessaging!Microsoft::CoreUI::Dispatch::UserAdapter_WindowProc
user32!UserCallWinProcCheckWow
user32!DispatchClientMessage
user32!_fnDWORD
ntdll!KiUserCallbackDispatcherContinue
win32u!NtUserPeekMessage
user32!_PeekMessage
user32!PeekMessageW
combase!CCliModalLoop::MyPeekMessage
combase!CCliModalLoop::PeekRPCAndDDEMessage
combase!CCliModalLoop::BlockFn
combase!ModalLoop [inline]
combase!ClassicSTAThreadWaitForCall
combase!ThreadSendReceive [inline]
combase!CSyncClientCall::SwitchAptAndDispatchCall [inline]
combase!CSyncClientCall::SendReceive2
combase!SyncClientCallRetryContext::SendReceiveWithRetry [inline]
combase!CSyncClientCall::SendReceiveInRetryContext [inline]
combase!ClassicSTAThreadSendReceive
combase!CSyncClientCall::SendReceive
combase!CClientChannel::SendReceive
combase!NdrExtpProxySendReceive
rpcrt4!NdrpClientCall3
combase!ObjectStublessClient
combase!ObjectStubless
DataExchange!DropTargetInternal::DragInfo::get_Data
Windows_UI_Xaml!DirectUI::DragEventArgs::get_DataViewImpl
Windows_UI_Xaml!DirectUI::DragEventArgsGenerated::get_DataView
Microsoft_Terminal_Control!
  winrt::impl::consume_Windows_UI_Xaml_IDragEventArgs2<
    winrt::Windows::UI::Xaml::DragEventArgs>::DataView
Microsoft_Terminal_Control!
  winrt::Microsoft::Terminal::Control::implementation::
  TermControl::_DragOverHandler+0x3b
Microsoft_Terminal_Control!TermControlT<...>::Connect::<DragOver lambda> [inline]
Microsoft_Terminal_Control!winrt::impl::delegate<...>::Invoke
Windows_UI_Xaml!DirectUI::CRoutedEventSourceBase<...>::Raise
Windows_UI_Xaml!DirectUI::CRoutedEventSourceBase<...>::UntypedRaise
Windows_UI_Xaml!DirectUI::DependencyObject::FireEvent
Windows_UI_Xaml!DirectUI::DXamlCore::FireEvent [inline]
Windows_UI_Xaml!AgCoreCallbacks::FireEvent [inline]
Windows_UI_Xaml!CFxCallbacks::JoltHelper_FireEvent [inline]
Windows_UI_Xaml!CCoreServices::CLR_FireEvent
Windows_UI_Xaml!CommonBrowserHost::CLR_FireEvent
Windows_UI_Xaml!CControlBase::ScriptCallback
Windows_UI_Xaml!CXcpDispatcher::OnScriptCallback
Windows_UI_Xaml!CXcpDispatcher::OnReentrancyProtectedWindowMessage
Windows_UI_Xaml!CXcpDispatcher::ProcessMessage [inline]
Windows_UI_Xaml!CXcpDispatcher::WindowProc
user32!UserCallWinProcCheckWow
user32!DispatchClientMessage
user32!_fnDWORD
ntdll!KiUserCallbackDispatcherContinue
win32u!NtUserMessageCall
user32!SendMessageWorker
user32!SendMessageW
Windows_UI_Xaml!CXcpDispatcher::SendMessageW [inline]
Windows_UI_Xaml!CXcpBrowserHost::SyncScriptCallbackRequest
Windows_UI_Xaml!CEventManager::RaiseHelper
Windows_UI_Xaml!CEventManager::Raise
Windows_UI_Xaml!CDragDropState::RaiseDragOverOrDropEvents
Windows_UI_Xaml!CDragDropState::RaiseEvents
Windows_UI_Xaml!ContentRootInput::DragDropProcessor::ProcessWinRtDragDrop
Windows_UI_Xaml!DragDrop_RaiseEvent
Windows_UI_Xaml!DirectUI::DropOperationTarget::RaiseDragDropEventActionAsync
Windows_UI_Xaml!DirectUI::RaiseDragDropEventAsyncOperation::OnStart
Windows_UI_Xaml!Microsoft::WRL::AsyncBase<...>::Start
Windows_UI_Xaml!DirectUI::DXamlAsyncBaseImpl<...>::StartOperation [inline]
Windows_UI_Xaml!DirectUI::DropOperationTarget::RaiseDragDropEventOperationAsync
Windows_UI_Xaml!DirectUI::DropOperationTarget::OverAsync
DataExchange!DropTargetInternal::DragOver
rpcrt4!Invoke
rpcrt4!Ndr64StubWorker
rpcrt4!NdrStubCall3
combase!CStdStubBuffer_Invoke
rpcrt4!CStdStubBuffer_Invoke
combase!InvokeStubWithExceptionPolicyAndTracing [inline]
combase!DefaultStubInvoke
combase!SyncStubCall::Invoke [inline]
combase!SyncServerCall::StubInvoke
combase!StubInvoke [inline]
combase!ServerCall::ContextInvoke
combase!CServerChannel::ContextInvoke [inline]
combase!DefaultInvokeInApartment [inline]
combase!ReentrantSTAInvokeInApartment
combase!AppInvoke [inline]
combase!ComInvokeWithLockAndIPID
combase!ComInvoke [inline]
combase!ThreadDispatch [inline]
combase!ThreadWndProc
user32!UserCallWinProcCheckWow
user32!DispatchMessageWorker
WindowsTerminal!WindowEmperor::HandleCommandlineArgs
WindowsTerminal!wWinMain
WindowsTerminal!invoke_main [inline]
WindowsTerminal!__scrt_common_main_seh
kernel32!BaseThreadInitThunk
ntdll!RtlUserThreadStart

Root cause analysis

The stack shows a XAML dispatcher reentrancy fail-fast caused by synchronously retrieving the drag payload from inside Terminal's DragOver handler:

  1. An OLE/WinRT drag operation raises DragOver over TermControl.
  2. TermControl::_DragOverHandler immediately calls e.DataView().
  3. DataView() enters DataExchange!DropTargetInternal::DragInfo::get_Data, which performs a synchronous cross-apartment COM request.
  4. Because this is an STA call, COM enters CCliModalLoop and pumps window messages while waiting for the request.
  5. The nested message pump dispatches pending XAML work through CDeferredInvoke::DispatchQueuedMessage.
  6. That queued work re-enters CXcpDispatcher::OnReentrancyProtectedWindowMessage while the original XAML drag dispatch is still active.
  7. XAML detects the prohibited reentrancy and deliberately fail-fasts with E_UNEXPECTED (0x8000ffff), surfaced by WER as 0xc000027b.

This is not a cmd.exe crash, an out-of-memory failure, or the Atlas renderer/history-buffer crash fixed elsewhere. The immediate unsafe operation is the synchronous e.DataView() getter during DragOver.

High output/large scrollback appears to be a timing amplifier, not the direct corrupt object. Under heavy output, XAML has more deferred render/layout/scroll work available for the COM modal loop to dispatch, increasing the chance of prohibited nested dispatch. That interpretation is consistent with the stack and repeatability, but it should be treated as a timing hypothesis until confirmed with instrumentation.

Current source path

The crashing release and current main contain materially the same handler in src/cascadia/TerminalControl/TermControl.cpp:

void TermControl::_DragOverHandler(..., const DragEventArgs& e)
{
    if (_IsClosing())
    {
        return;
    }

    if (!(e.DataView().Contains(StandardDataFormats::StorageItems()) ||
          e.DataView().Contains(StandardDataFormats::Text())))
    {
        return;
    }

    e.AcceptedOperation(DataPackageOperation::Copy);

    if (e.DataView().Contains(StandardDataFormats::StorageItems()))
    {
        ...
    }
    else if (e.DataView().Contains(StandardDataFormats::Text()))
    {
        ...
    }
}

This evaluates the synchronous DataView() getter up to four times for one drag-over callback. The representative crash occurs at _DragOverHandler+0x3b, during the first getter evaluation.

Internal tab drags already place private windowId and pid properties into their data package in TerminalPage::_onTabDragStarting. They are unrelated to the file/text drop support in TermControl, so allowing the routed event to reach the terminal content handler creates unnecessary exposure to this synchronous payload retrieval.

Suggested mitigation/fix

The safest Terminal-side mitigation is to prevent internal tab drags from entering the terminal content drop handler at all:

  1. Set an internal-tab-drag-in-progress flag at TabDragStarting and clear it on every completion/cancel/drop-outside path.
  2. Before calling e.DataView(), have TermControl::_DragOverHandler return immediately when that flag is set; alternatively, temporarily set AllowDrop=false on terminal controls for the lifetime of an internal tab drag.
  3. Preserve existing tab-strip handling for moving tabs between windows.
  4. For external file/text drags, cache const auto dataView = e.DataView() rather than evaluating the getter repeatedly.
  5. Consider moving external payload inspection out of high-frequency DragOver where possible and into Drop/an asynchronous path.

A time-based throttle/debounce is not a complete fix: the first DataView() call can trigger the fail-fast. A C++ try/catch around e.DataView() is also unlikely to contain this failure because XAML calls RaiseFailFastException from the nested dispatcher before the getter returns.

Acceptance criteria

  • Add a focused RED reproduction/stress test or diagnostic harness that performs internal tab drags across terminal content while output is continuously updating; demonstrate that it can exercise the unsafe path before the fix and no longer does afterward.
  • Internal tab drag/reorder/tear-out never invokes TermControl::_DragOverHandler's DataView() payload retrieval.
  • Repeated internal tab drags across terminal content under heavy output do not produce 0xc000027b / Windows.UI.Xaml.dll+0x481782 on Windows 10 19045.
  • Cross-window tab movement, same-window tab reordering, and tab tear-out continue to work.
  • External file and text drop into terminal content continue to work.
  • The fix does not rely only on notification throttling or exception handling around a fail-fast path.

Related issues

  • #18719 is an exact prior match: tab drag on Windows 10, 0xc000027b, Windows.UI.Xaml.dll, and the same fault offset 0x481782. It was closed by the stale bot after the original reporter could not provide the requested dump. The full dumps described here provide the missing evidence.

Additional triage notes

  • This is distinct from #20366, which fixed a c0000005 crash in AtlasEngine::PaintCursor associated with heavy buffers/tab merging. There is no AtlasEngine frame here, and the failure code/bucket differ.
  • This is distinct from #19026, which guards a null storage-item result after dropping a relative path. This crash occurs during DragOver, before a drop payload is consumed.
  • The current main handler still performs the same synchronous DataView() calls, so no available Terminal update appears to contain a fix as of 2026-08-05.

Dump availability and privacy

Two full user-mode dumps are available privately to the Terminal maintainers. They are approximately 806 MB and 852 MB. They should not be attached publicly because full Terminal dumps may contain terminal buffer contents, command lines, environment data, and other sensitive information.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs-Tag-FixDoesn't match tag requirementsNeeds-TriageIt's a new issue that the core contributor team needs to triage at the next triage meeting

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions