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

qt5.2 crash due to accessing destroyed QWidgetWindow

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Done
    • Icon: P3: Somewhat important P3: Somewhat important
    • 5.2.1
    • 5.2.0
    • None
    • Windows 7 x64
      VS2010
    • 8fcab70408628f730860d3861a06fc519d069f5e (14.12.2013)

      In some circumstances Qt 5.2 will crash due to accessing destroyed QWidgetWindow object. The attched sample program can reproduce this issue, just build it in debug mode and run it, press button named 'Push Me To Crash!' you can see the crash.

      The logic behind the crash is explained below:
      In this sample program, I first created a QSplitter widget 'splitter' without parent widget and add some offspring widgets to it, among them there is a QGLWidget widget 'glW', and then I create a top level widget 'topW' and set its parent to one of the offspring widget of 'splitter' and show the widget 'topW', this will make qt5 call createWinId() to 'topW's ancestor widget 'splitter', in createWinId() of 'splitter' it will call q_createNativeChildrenAndSetParent() to create all native children recursively and finally make 'glW's QWidgetWindow object become the child of 'splitter's QWidgetWindow object. Then I add 'splitter' to a stacked widget and show it, this will make qt5 call setParent_sys() to 'splitter'. According to the code in setParent_sys():

          // Reparenting toplevel to child
          if (wasCreated && !(f & Qt::Window) && (oldFlags & Qt::Window) && !q->testAttribute(Qt::WA_NativeWindow)) {
              if (extra && extra->hasWindowContainer)
                  QWindowContainer::toplevelAboutToBeDestroyed(q);
              q->destroy();
          }
      

      qt5 will call destroy() to 'splitter', in QWidget::destroy() it will first call destroy() to its child widgets recursively:

              if (destroySubWindows) {
                  QObjectList childList(children());
                  for (int i = 0; i < childList.size(); i++) {
                      QWidget *widget = qobject_cast<QWidget *>(childList.at(i));
                      if (widget && widget->testAttribute(Qt::WA_NativeWindow)) {
                          if (widget->windowHandle()) {
                              widget->destroy();
                          }
                      }
                  }
              }
      

      Since 'splitter's child widgets (one of them is the parent of 'glW') don't have Qt::WA_NativeWindow set, 'glW' will not be destroyed. And then deleteTLSysExtra() will be called to 'splitter', in this function 'splitter's QWidgetWindow object will be deleted(and recursively deleted its child objects), remember that 'glW's QWidgetWindow object is a child of QWidgetWindow object of 'splitter' so it will be deleted too, this will make 'glW's topextra structure hold a deleted pointer of QWidgetWindow, that is the source of the crash later.

        1. qtbug35600_diag.patch
          3 kB
        2. qtbug35600.txt
          9 kB
        3. qtbug35600.zip
          4 kB
        4. testQt5Crash.rar
          5 kB
        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

            peppe Giuseppe D'Angelo
            jianliang79 liang jian
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved:

                There are no open Gerrit changes