Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-126303

QWidget::createWindowContainer() managed window deleted when new widget added due to QRhi

    XMLWordPrintable

Details

    • All
    • 006cbf658 (dev), f0f9cc602 (6.8), 0673dde3f (6.7)

    Description

      Steps to reproduce:

      1. Run the program below:
      #include <iostream>
      #include <QApplication>
      #include <QTabWidget>
      #include <QWindow>
      #include <QQuickWidget>
      
      class MyWindow : public QWindow
      {
      public:
          MyWindow() {
              std::cerr << "MyWindow::MyWindow(). this=" << std::hex << this << std::endl;
          }
      
          ~MyWindow() {
              std::cerr << "MyWindow::~MyWindow(). this=" << std::hex << this << std::endl;
          }
      };
      
      int main(int argc, char *argv[])
      {
          QApplication app(argc, argv);
      
          QTabWidget tab_widget;
          tab_widget.show();
      
          const auto w1 = QWidget::createWindowContainer(new MyWindow(), &tab_widget);
          tab_widget.addTab(w1, QStringLiteral("MyWindow tab"));
      
          // Trigger condition. During the execution of this statement MyWindow will unexpectedly
          // be deleted.
          tab_widget.addTab(new QQuickWidget(), QStringLiteral("QQuickWidget tab"));
      
          return QCoreApplication::exec();
      }
      
      Expected result:

      The program runs

      Actual result:

      The program crashes.

      The program crashes because the MyWindow instanced added via QWidget::createWindowContainer() is unexpectedly deleted when the second tab, "QQuickWidget tab", is added. This happens because of the call to newtlw->destroy() in the following code from https://code.qt.io/cgit/qt/qtbase.git/commit/?id=68a4c5da9a080101cccd8a3b2edb1c908da0ca8e

      void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
      {
          ...
      
          if (oldtlw != newtlw) {
              ...
              if (q_evaluateRhiConfig(this, nullptr, &surfaceType)) {
              ...
      
                  if (recreate) {
                      const auto windowStateBeforeDestroy = newtlw->windowState();
                      const auto visibilityBeforeDestroy = newtlw->isVisible();
                      newtlw->destroy(); // <--- Causes the window created with QWidget::createWindowContainer() to be deleted
                      newtlw->create();
                      Q_ASSERT(newtlw->windowHandle());
                      newtlw->windowHandle()->setWindowStates(windowStateBeforeDestroy);
                      QWidgetPrivate::get(newtlw)->setVisible(visibilityBeforeDestroy);
                  }
      

      The stacktrace for the destruction of the MyWindow instance:

      MyWindow::~MyWindow(MyWindow * const this) (/home/ts/src/easyviz/qtutility/examples/example2.cc:15)
      MyWindow::~MyWindow(MyWindow * const this) (/home/ts/src/easyviz/qtutility/examples/example2.cc:16)
      libQt6Core.so.6!QObjectPrivate::deleteChildren(QObjectPrivate * const this) (/home/ts/src/qt5-2/qtbase/src/corelib/kernel/qobject.cpp:2216)
      libQt6Core.so.6!QObject::~QObject(QObject * const this) (/home/ts/src/qt5-2/qtbase/src/corelib/kernel/qobject.cpp:1168)
      libQt6Gui.so.6!QWindow::~QWindow(QWindow * const this) (/home/ts/src/qt5-2/qtbase/src/gui/kernel/qwindow.cpp:203)
      libQt6Widgets.so.6!QWidgetWindow::~QWidgetWindow(QWidgetWindow * const this) (/home/ts/src/qt5-2/qtbase/src/widgets/kernel/qwidgetwindow.cpp:156)
      libQt6Widgets.so.6!QWidgetWindow::~QWidgetWindow(QWidgetWindow * const this) (/home/ts/src/qt5-2/qtbase/src/widgets/kernel/qwidgetwindow.cpp:156)
      libQt6Widgets.so.6!QWidgetPrivate::deleteTLSysExtra(QWidgetPrivate * const this) (/home/ts/src/qt5-2/qtbase/src/widgets/kernel/qwidget.cpp:1705)
      libQt6Widgets.so.6!QWidget::destroy(QWidget * const this, bool destroyWindow, bool destroySubWindows) (/home/ts/src/qt5-2/qtbase/src/widgets/kernel/qwidget.cpp:12585)
      libQt6Widgets.so.6!QWidget::setParent(QWidget * const this, QWidget * parent, Qt::WindowFlags f) (/home/ts/src/qt5-2/qtbase/src/widgets/kernel/qwidget.cpp:10929)
      libQt6Widgets.so.6!QWidget::setParent(QWidget * const this, QWidget * parent) (/home/ts/src/qt5-2/qtbase/src/widgets/kernel/qwidget.cpp:10710)
      libQt6Widgets.so.6!QLayout::addChildWidget(QLayout * const this, QWidget * w) (/home/ts/src/qt5-2/qtbase/src/widgets/kernel/qlayout.cpp:863)
      libQt6Widgets.so.6!QStackedLayout::insertWidget(QStackedLayout * const this, int index, QWidget * widget) (/home/ts/src/qt5-2/qtbase/src/widgets/kernel/qstackedlayout.cpp:191)
      libQt6Widgets.so.6!QStackedWidget::insertWidget(QStackedWidget * const this, int index, QWidget * widget) (/home/ts/src/qt5-2/qtbase/src/widgets/widgets/qstackedwidget.cpp:146)
      libQt6Widgets.so.6!QTabWidget::insertTab(QTabWidget * const this, int index, QWidget * w, const QIcon & icon, const QString & label) (/home/ts/src/qt5-2/qtbase/src/widgets/widgets/qtabwidget.cpp:440)
      libQt6Widgets.so.6!QTabWidget::insertTab(QTabWidget * const this, int index, QWidget * w, const QString & label) (/home/ts/src/qt5-2/qtbase/src/widgets/widgets/qtabwidget.cpp:419)
      libQt6Widgets.so.6!QTabWidget::addTab(QTabWidget * const this, QWidget * child, const QString & label) (/home/ts/src/qt5-2/qtbase/src/widgets/widgets/qtabwidget.cpp:363)
      main(int argc, char ** argv) (/home/ts/src/easyviz/qtutility/examples/example2.cc:31)
      

      The problem reproduces on both the platforms I have access to, Linux and Windows, with exactly the same stacktrace.

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            vestbo Tor Arne Vestbø
            ts Thomas Sondergaard
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: