Skip to content

Fix double-removal Q_ASSERT in DockManagerPrivate::restoreStateFromXml#838

Open
fdarmayan wants to merge 1 commit into
githubuser0xFFFF:masterfrom
fdarmayan:lp360-patches
Open

Fix double-removal Q_ASSERT in DockManagerPrivate::restoreStateFromXml#838
fdarmayan wants to merge 1 commit into
githubuser0xFFFF:masterfrom
fdarmayan:lp360-patches

Conversation

@fdarmayan
Copy link
Copy Markdown

Problem

CDockManager::restoreState() can crash with a failed assertion when the
saved state contains floating dock containers. The teardown path in
DockManagerPrivate::restoreStateFromXml() looks like:

for (int i = 0; i < FloatingWidgets.count(); ++i)
{
    CFloatingDockContainer* floatingWidget = FloatingWidgets[i];
    if (!floatingWidget) continue;
    _this->removeDockContainer(floatingWidget->dockContainer());
    floatingWidget->deleteLater();
}

removeDockContainer() is called and the floating widget is queued for
deletion. When the queued deleteLater() fires, ~CDockContainerWidget()
runs and calls removeDockContainer() on the manager a second time for
the same container. That second call trips:

Q_ASSERT(removed == 1);

inside CDockManager::removeDockContainer(), killing the application in
debug builds and silently corrupting the container list in release.

Fix

Use CDockContainerWidget::removeFromDockManager() (introduced in
544c624 "Unbind containers from DockManager to prevent accidental reuse
before deletion") instead of the manager-side removeDockContainer().
That helper clears the container's back-pointer to the manager up front,
so the subsequent destructor call becomes a no-op for the manager and
the assertion no longer fires.

floatingWidget->dockContainer()->removeFromDockManager();
floatingWidget->deleteLater();

Repro

  1. Open an app that uses CDockManager with at least one floating dock
    container in the saved layout.
  2. Call CDockManager::saveState() / restoreState() on that layout
    while floating widgets exist.
  3. Observe the Q_ASSERT(removed == 1) failure in
    CDockManager::removeDockContainer() once deleteLater() drains.

Notes

  • One-line change, no new public API.
  • Behaviour-preserving: removeFromDockManager() already does the
    same list-removal work that removeDockContainer() did, just without
    the double-removal hazard.

In DockManagerPrivate::restoreStateFromXml() the floating widgets were
removed via removeDockContainer() and then queued for deletion with
deleteLater(). When ~CDockContainerWidget() ran it would call
removeDockContainer() a second time on the same container, tripping the
Q_ASSERT(removed == 1) check in CDockManager::removeDockContainer().

Switch to CDockContainerWidget::removeFromDockManager() (introduced in
upstream 544c624) so the container's back-pointer to the manager is
cleared up front and the destructor becomes a no-op for the manager
side. This keeps the LP360_AI workspace restore path crash-free until
the equivalent fix lands upstream.
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