Skip to content

Close open dialogs when a secondary view is consolidated - #3415

Open
FrayxRulez wants to merge 1 commit into
developfrom
close-dialogs-on-consolidate
Open

Close open dialogs when a secondary view is consolidated#3415
FrayxRulez wants to merge 1 commit into
developfrom
close-dialogs-on-consolidate

Conversation

@FrayxRulez

Copy link
Copy Markdown
Collaborator

NativeException / ACCESS_VIOLATION, reported by crash telemetry on 12.10.2.0 (X64).

   7  DirectUI::ContentDialog::DetachEventHandlersForOpenDialog+0x46
      onecoreuap\windows\dxaml\xcp\dxaml\lib\contentdialog_partial.cpp:2507
   8  DirectUI::ContentDialog::~ContentDialog+0x1f
      onecoreuap\windows\dxaml\xcp\dxaml\lib\contentdialog_partial.cpp:74
   9  ctl::ComObject<DirectUI::ContentDialog>::`scalar deleting destructor'+0x18
  10  ctl::WeakReferenceSourceNoThreadId::OnFinalReleaseOffThread+0x2c8694
      onecoreuap\windows\dxaml\xcp\components\lifetime\lib\weakreferencesourcenothreadid.cpp:796
  11  DirectUI::DependencyObject::OnFinalRelease+0xe
  12  ctl::ComBase::ReleaseImpl+0x87
  13  ComWrappers.NativeObjectWrapper.Release()
  15  ComWrappers.NativeObjectWrapper.Finalize()
  16  System.Runtime.__Finalizer.DrainQueue()
  18  FinalizerStart

Cause

The finalizer thread releases the last reference to a ContentDialog that belonged to a
secondary view whose XAML core is already gone. OnFinalReleaseOffThread cannot post the
delete back to that view, so it runs ~ContentDialog inline on the finalizer thread; the
dialog is still marked open, the destructor takes DetachEventHandlersForOpenDialog, and
that faults.

This is the same class of failure OnShutdownStarting's drain already exists to prevent —
collect the view's RCWs while its thread still pumps and XAML is still up, so nothing is
released past the dead core. An open ContentDialog slips through it: it is parented to
the popup root, not to Window.Content, so OnConsolidated's _window.Content = null
does not unroot it. The native tree still holds its peer, the drain has nothing to collect,
and the dialog is finalized whenever a later GC happens to run.

The log tail from a report matches that exactly. A share target window opens a
ChooseChatsPopup, is closed with the dialog still up, and drains clean and fast — 234ms
then 187ms, nowhere near the 2s timeout, which is the "still reference-tracked by the
native tree, nothing here to collect" outcome the diagnostic comment in Drain describes.
Thirty seconds later a new share target window opens its own popup, and the allocation
collects the previous dialog: the crash lands ~1.2s after that second popup is shown.

ShareWindow never hides its ChooseChatsPopup, so it is the easiest way in, but nothing
about this is specific to the share target — any secondary view closed with a dialog open
gets there.

Change

OnConsolidated now hides any open ContentDialog for the view before it drops the
content. Placed before OnClosed, which detaches the content and with it XamlRoot.

Kept inside the NET9_0_OR_GREATER block with the rest of the teardown machinery it feeds,
since that is where the drain lives and where the reports come from; it is a one-word change
to apply it on both flavors.

Notes

Not built or run — a UWP build was not available here. The file parses clean under Roslyn
with the symbol both defined and undefined; that catches syntax, not types.

One residual: ContentDialog.Hide() starts a close transition that needs a rendered frame
to finish, and the app's own ContentPopup completion signal (QueueCallbackForCompositionRendered)
needs one too. The shutdown deferral keeps the thread pumping and the drain is queued behind
it at Low, so it should get there — but if reports continue on this stack, forcing
popup.IsOpen = false after the Hide() unroots it without waiting for a frame, and that
is the next thing to try.

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.

1 participant