QComboBox: close the container explicitly before destroying it

QComboBox destroys the container of the view in its own destructor,
before the QWidget destructor is entered. The container is a toplevel
widget, so destroying that will destroy a platform window, triggering an
accessibility update cycle that calls back into Qt. As the QComboBox has
not yet reached the QWidget destructor, it still considers itself as
visible and focused. The accessibility query will therefore operate on
it, as the focused object. Probing the state accesses the view.

The view however is already partially destroyed, as the container's
destruction has already passed the QWidget destructor deleting all its
children. As a result, we are returning a pointer to a QAbstractItemView
that's already in the QWidget destructor, resulting in a crash.

Options for fixing this would be resetting the view pointer in
~QComboBoxPrivateContainer to nullptr and to test for that in client
code. Doing that triggered crashes in tests, as QComboBox::view() so far
has never returned a nullptr no matter the state of the combobox.

So instead, close the container explicitly before destroying it. This
way, any update cycle resulting in reentrancy (such as accessibility of
backingstore flushing when the container closes) will be completed
before objects are destroyed.

This amends fde358dd9069d0695f113ec6ba98efebedd1e520, which added the
explicit destruction of the container, for similar reasons.

This seems to be a combobox-specific problem due to the combination of
explicit destruction of (toplevel) child widgets, resulting event
processing, and exposing of internal widget states through public API
as part of the widget's accessible state.

Pick-to: 6.8 6.5
Fixes: QTBUG-132310
Change-Id: I74df5b71906ce8153b12ddc35b897a44e7752907
Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
(cherry picked from commit 74e5a51babe0a133ce0fe9b907ef77cc606fbcb9)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Volker Hilsheimer 2025-03-20 18:58:33 +01:00 committed by Qt Cherry-pick Bot
parent d3e03d1da0
commit 4874a7b13c
2 changed files with 9 additions and 3 deletions

View File

@ -441,7 +441,7 @@ QAccessible::State QAccessibleComboBox::state() const
if (QComboBox *cBox = comboBox()) {
s.expandable = true;
s.expanded = isValid() && cBox->view()->isVisible();
s.expanded = isValid() && cBox->view() && cBox->view()->isVisible();
s.editable = cBox->isEditable();
}
return s;

View File

@ -1472,8 +1472,14 @@ QComboBox::~QComboBox()
; // objects can't throw in destructor
}
// Dispose of container before QComboBox goes away
delete d->container;
// Dispose of container before QComboBox goes away. Close explicitly so that
// update cycles back into the combobox (e.g. from accessibility when the
// active window changes) are completed first.
if (d->container) {
d->container->close();
delete d->container;
d->container = nullptr;
}
}
/*!