From 4e396bcdc442d5d6e5174a2d7a4073d929b8ee30 Mon Sep 17 00:00:00 2001 From: Axel Spoerl Date: Fri, 12 Apr 2024 17:53:19 +0200 Subject: [PATCH] Fix crash in QMainWindow:.tabifiedDockWidgets() QMainWindow:.tabifiedDockWidgets() was refactored in Qt 6.6.3, because it returned wrong values. It now loops from 0 to QMainWindowTabBar::count() and uses QMainWindowTabBar::dockAt(), to get the dock widget pointer for an index. When a dock widget is removed from a floating tab, event processing is necessary for the item_list and QMainWindowTabBar::count() to get in sync. This case was overlooked in the refactoring. It can lead to dockAt() being called with an out-of-bounds index, which it asserted. The assertion triggered, when QMainWindow::removeDockWidget() and QMainWindow::tabifiedDockWidgets() were called right after each other, without processing events inbetween. QMainWindowTabBar::dockWidgets() doesn't add nullptr to the list, it returns. Therefore, return nullptr, when dockAt() is called out-of-bounds. Add test functionality in tst_QDockWidget::updateTabBarOnVisibilityChanged(). Fixes: QTBUG-124262 Pick-to: 6.5 Change-Id: If66084b9f00b4e39f7a620da68df67c735029cf1 Reviewed-by: Volker Hilsheimer (cherry picked from commit f97e60a4f0602e1478c888ff1043276966c93387) Reviewed-by: Qt Cherry-pick Bot Reviewed-by: Axel Spoerl --- src/widgets/widgets/qmainwindowlayout.cpp | 16 +++++++++++++--- .../widgets/qdockwidget/tst_qdockwidget.cpp | 3 +++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/widgets/widgets/qmainwindowlayout.cpp b/src/widgets/widgets/qmainwindowlayout.cpp index db17e50d5c2..85c58fd70f5 100644 --- a/src/widgets/widgets/qmainwindowlayout.cpp +++ b/src/widgets/widgets/qmainwindowlayout.cpp @@ -1931,6 +1931,11 @@ bool QMainWindowTabBar::contains(const QDockWidget *dockWidget) const return false; } +// When a dock widget is removed from a floating tab, +// Events need to be processed for the tab bar to realize that the dock widget is gone. +// In this case count() counts the dock widget in transition and accesses dockAt +// with an out-of-bounds index. +// => return nullptr in contrast to other xxxxxAt() functions QDockWidget *QMainWindowTabBar::dockAt(int index) const { QMainWindowTabBar *that = const_cast(this); @@ -1938,10 +1943,15 @@ QDockWidget *QMainWindowTabBar::dockAt(int index) const QDockAreaLayoutInfo *info = mlayout->dockInfo(that); if (!info) return nullptr; + const int itemIndex = info->tabIndexToListIndex(index); - Q_ASSERT(itemIndex >= 0 && itemIndex < info->item_list.count()); - const QDockAreaLayoutItem &item = info->item_list.at(itemIndex); - return item.widgetItem ? qobject_cast(item.widgetItem->widget()) : nullptr; + if (itemIndex >= 0) { + Q_ASSERT(itemIndex < info->item_list.count()); + const QDockAreaLayoutItem &item = info->item_list.at(itemIndex); + return item.widgetItem ? qobject_cast(item.widgetItem->widget()) : nullptr; + } + + return nullptr; } void QMainWindowTabBar::mouseMoveEvent(QMouseEvent *e) diff --git a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp index 63a432578e9..af62d0d0899 100644 --- a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp +++ b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp @@ -716,6 +716,9 @@ void tst_QDockWidget::updateTabBarOnVisibilityChanged() QCOMPARE(tabBar->currentIndex(), 0); QCOMPARE(mw.tabifiedDockWidgets(dw2), {dw3}); + + mw.removeDockWidget(dw3); + QCOMPARE(mw.tabifiedDockWidgets(dw2).count(), 0); } Q_DECLARE_METATYPE(Qt::DockWidgetArea)