Details
-
Bug
-
Resolution: Done
-
P3: Somewhat important
-
5.2.0
-
None
-
Windows 7 x64
VS2010
-
8fcab70408628f730860d3861a06fc519d069f5e (14.12.2013)
Description
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.