summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@kdab.com>2016-07-11 19:55:24 +0200
committerMarc Mutz <marc.mutz@kdab.com>2017-02-06 14:41:46 +0000
commitc876bb1f1333e47722e202b0916415e771137071 (patch)
tree34401974dd6a2993561b577b07b20955a696adb7 /tests
parentbbd091ac5853d7884929369da4e1b5d233ca504c (diff)
QInputDialog: prevent crash in static get*() functions when parent gets deleted
As explained in https://blogs.kde.org/2009/03/26/how-crash-almost-every-qtkde-application-and-how-fix-it-0 creating dialogs on the stack is a bad idea if the application or the dialog's parent window can be closed by means other than user interaction (such as a timer or an IPC call). Since we cannot know whether Qt is used to build such an application, we must assume it is, create the dialog on the heap, and monitor its lifetime with a QPointer. Instead of using manual resource management, add a minimal implementation of QAutoPointer, and use that in all static get*() functions. Task-number: QTBUG-54693 Change-Id: I6157dca18608e02be1ea2c2defbc31641defc9d1 Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> Reviewed-by: David Faure <david.faure@kdab.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/widgets/dialogs/qinputdialog/qinputdialog.pro2
-rw-r--r--tests/auto/widgets/dialogs/qinputdialog/tst_qinputdialog.cpp71
2 files changed, 72 insertions, 1 deletions
diff --git a/tests/auto/widgets/dialogs/qinputdialog/qinputdialog.pro b/tests/auto/widgets/dialogs/qinputdialog/qinputdialog.pro
index cc479812a8..9cb14c5350 100644
--- a/tests/auto/widgets/dialogs/qinputdialog/qinputdialog.pro
+++ b/tests/auto/widgets/dialogs/qinputdialog/qinputdialog.pro
@@ -1,4 +1,4 @@
CONFIG += testcase
TARGET = tst_qinputdialog
-QT += widgets testlib
+QT += widgets-private testlib
SOURCES += tst_qinputdialog.cpp
diff --git a/tests/auto/widgets/dialogs/qinputdialog/tst_qinputdialog.cpp b/tests/auto/widgets/dialogs/qinputdialog/tst_qinputdialog.cpp
index bbb6883238..0ea9e0259f 100644
--- a/tests/auto/widgets/dialogs/qinputdialog/tst_qinputdialog.cpp
+++ b/tests/auto/widgets/dialogs/qinputdialog/tst_qinputdialog.cpp
@@ -35,6 +35,7 @@
#include <QComboBox>
#include <QDialogButtonBox>
#include <qinputdialog.h>
+#include <QtWidgets/private/qdialog_p.h>
class tst_QInputDialog : public QObject
{
@@ -52,6 +53,7 @@ private slots:
void getInt();
void getDouble_data();
void getDouble();
+ void taskQTBUG_54693_crashWhenParentIsDeletedWhileDialogIsOpen();
void task255502getDouble();
void getText_data();
void getText();
@@ -311,6 +313,75 @@ void tst_QInputDialog::getDouble()
delete parent;
}
+namespace {
+class SelfDestructParent : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit SelfDestructParent(int delay = 100)
+ : QWidget(Q_NULLPTR)
+ {
+ QTimer::singleShot(delay, this, SLOT(deleteLater()));
+ }
+};
+}
+
+void tst_QInputDialog::taskQTBUG_54693_crashWhenParentIsDeletedWhileDialogIsOpen()
+{
+ // getText
+ {
+ QAutoPointer<SelfDestructParent> dialog(new SelfDestructParent);
+ bool ok = true;
+ const QString result = QInputDialog::getText(dialog.get(), "Title", "Label", QLineEdit::Normal, "Text", &ok);
+ QVERIFY(!dialog);
+ QVERIFY(!ok);
+ QVERIFY(result.isNull());
+ }
+
+ // getMultiLineText
+ {
+ QAutoPointer<SelfDestructParent> dialog(new SelfDestructParent);
+ bool ok = true;
+ const QString result = QInputDialog::getMultiLineText(dialog.get(), "Title", "Label", "Text", &ok);
+ QVERIFY(!dialog);
+ QVERIFY(!ok);
+ QVERIFY(result.isNull());
+ }
+
+ // getItem
+ for (int editable = false; editable <= true; ++editable) {
+ QAutoPointer<SelfDestructParent> dialog(new SelfDestructParent);
+ bool ok = true;
+ const QString result = QInputDialog::getItem(dialog.get(), "Title", "Label",
+ QStringList() << "1" << "2", 1, editable, &ok);
+ QVERIFY(!dialog);
+ QVERIFY(!ok);
+ QCOMPARE(result, QLatin1String("2"));
+ }
+
+ // getInt
+ {
+ const int initial = 7;
+ QAutoPointer<SelfDestructParent> dialog(new SelfDestructParent);
+ bool ok = true;
+ const int result = QInputDialog::getInt(dialog.get(), "Title", "Label", initial, -10, +10, 1, &ok);
+ QVERIFY(!dialog);
+ QVERIFY(!ok);
+ QCOMPARE(result, initial);
+ }
+
+ // getDouble
+ {
+ const double initial = 7;
+ QAutoPointer<SelfDestructParent> dialog(new SelfDestructParent);
+ bool ok = true;
+ const double result = QInputDialog::getDouble(dialog.get(), "Title", "Label", initial, -10, +10, 2, &ok);
+ QVERIFY(!dialog);
+ QVERIFY(!ok);
+ QCOMPARE(result, initial);
+ }
+}
+
void tst_QInputDialog::task255502getDouble()
{
parent = new QWidget;