From 8fcab70408628f730860d3861a06fc519d069f5e Mon Sep 17 00:00:00 2001 From: Jian Liang Date: Sat, 14 Dec 2013 10:59:35 +0800 Subject: Avoid crash due to accessing deleted QWidgetWindow object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change childWidget->windowHandle() to childWidget->internalWinId() in q_createNativeChildrenAndSetParent() to determine whether should we call childWidget->winId(). This is because in some circumstances Qt will crash due to accessing deleted QWidgetWindow object if we use windowHandle(). Think about the following scenario: 1) create a widget A without parent and add two child widgets B and C to A 2) create a native widget D as the child of B, note that when we set Qt::WA_NativeWindow attribute to it, its QWidgetWindow will be created which means its windowHandle() is not null. 3) create a top level widget E as the child of C and show it. This will make Qt call createWinId() to A and then q_createNativeChildrenAndSetParent() will be called to create A's native children recursively and finally make D's QWidgetWindow object become a child of A's QWidgetWindow object. Please note here that B will not become a native widget just because at that moment windowHandle() of D is not null and Qt will not call winId() to its parent B 4) Set A's parent to another widget which has been shown, setParent_sys() will be called to A and then Qt will call destroy() to A. in destroy() Qt will try to call destroy() to its children recursively with a condition that the child has Qt::WA_NativeWindow been set. But D's parent B is not a native widget right now so B and D is not destroyed. Qt will then deleted the QWidgetWindow object of A, since E's QWidgetWindow object is a child of A's QWidgetWindow object, it will also be deleted. Now E hold a deleted pointer of QWidgetWindow object. This is the source of crash later. Task-number: QTBUG-35600 Change-Id: I97a20a68e626ee62b15bb4eae580e26f8948923b Reviewed-by: Friedemann Kleint Reviewed-by: Jørgen Lind --- .../kernel/qwidget_window/tst_qwidget_window.cpp | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'tests') diff --git a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp index 1bbbfd610e..d6b7fc20ed 100644 --- a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp +++ b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp @@ -94,6 +94,8 @@ private slots: #ifndef QT_NO_DRAGANDDROP void tst_dnd(); #endif + + void tst_qtbug35600(); }; void tst_QWidget_window::initTestCase() @@ -568,5 +570,33 @@ void tst_QWidget_window::tst_dnd() } #endif +void tst_QWidget_window::tst_qtbug35600() +{ + QWidget w; + w.show(); + + QWidget *wA = new QWidget; + QHBoxLayout *layoutA = new QHBoxLayout; + + QWidget *wB = new QWidget; + layoutA->addWidget(wB); + + QWidget *wC = new QWidget; + layoutA->addWidget(wC); + + wA->setLayout(layoutA); + + QWidget *wD = new QWidget; + wD->setAttribute(Qt::WA_NativeWindow); + wD->setParent(wB); + + QWidget *wE = new QWidget(wC, Qt::Tool | Qt::FramelessWindowHint | Qt::WindowTransparentForInput); + wE->show(); + + wA->setParent(&w); + + // QTBUG-35600: program may crash here or on exit +} + QTEST_MAIN(tst_QWidget_window) #include "tst_qwidget_window.moc" -- cgit v1.2.3