diff options
-rw-r--r-- | src/widgets/dialogs/qprogressdialog.cpp | 7 | ||||
-rw-r--r-- | tests/auto/widgets/dialogs/qprogressdialog/tst_qprogressdialog.cpp | 24 |
2 files changed, 30 insertions, 1 deletions
diff --git a/src/widgets/dialogs/qprogressdialog.cpp b/src/widgets/dialogs/qprogressdialog.cpp index aaa4430c39..485e5cae49 100644 --- a/src/widgets/dialogs/qprogressdialog.cpp +++ b/src/widgets/dialogs/qprogressdialog.cpp @@ -51,6 +51,7 @@ #include "qpushbutton.h" #include "qtimer.h" #include "qelapsedtimer.h" +#include "qscopedvaluerollback.h" #include <private/qdialog_p.h> #include <limits.h> @@ -71,6 +72,7 @@ public: shown_once(false), cancellation_flag(false), setValue_called(false), + processingEvents(false), showTime(defaultShowTime), #ifndef QT_NO_SHORTCUT escapeShortcut(nullptr), @@ -94,6 +96,7 @@ public: bool shown_once; bool cancellation_flag; bool setValue_called; + bool processingEvents; QElapsedTimer starttime; int showTime; bool autoClose; @@ -660,8 +663,10 @@ void QProgressDialog::setValue(int progress) d->bar->setValue(progress); if (d->shown_once) { - if (isModal()) + if (isModal() && !d->processingEvents) { + const QScopedValueRollback guard(d->processingEvents, true); QCoreApplication::processEvents(); + } } else { if ((!d->setValue_called && progress == 0 /* for compat with Qt < 5.4 */) || progress == minimum()) { d->starttime.start(); diff --git a/tests/auto/widgets/dialogs/qprogressdialog/tst_qprogressdialog.cpp b/tests/auto/widgets/dialogs/qprogressdialog/tst_qprogressdialog.cpp index 6f527e7b6b..2149ee7c44 100644 --- a/tests/auto/widgets/dialogs/qprogressdialog/tst_qprogressdialog.cpp +++ b/tests/auto/widgets/dialogs/qprogressdialog/tst_qprogressdialog.cpp @@ -53,6 +53,7 @@ private Q_SLOTS: void QTBUG_31046(); void settingCustomWidgets(); void i18n(); + void setValueReentrancyGuard(); }; void tst_QProgressDialog::cleanup() @@ -291,5 +292,28 @@ void tst_QProgressDialog::i18n() QVERIFY(!btn->text().startsWith(xxx)); } +void tst_QProgressDialog::setValueReentrancyGuard() +{ + // Tests setValue() of window modal QProgressBar with + // Qt::QueuedConnection: + // This test crashes with a stack overflow if the boolean + // guard "processingEvents" that prevents reentranct calls + // to QCoreApplication::processEvents() within setValue() + // has not been implemented + + constexpr int steps = 100; // Should be at least 50 to test for crash + + QProgressDialog dlg("Testing setValue reentrancy guard...", QString(), 0, steps); + dlg.setWindowModality(Qt::WindowModal); + dlg.setMinimumDuration(0); + dlg.setAutoReset(false); + + // Simulate a quick work loop + for (int i = 0; i <= steps; ++i) + QMetaObject::invokeMethod(&dlg, "setValue", Qt::QueuedConnection, Q_ARG(int, i)); + + QTRY_COMPARE(dlg.value(), steps); +} + QTEST_MAIN(tst_QProgressDialog) #include "tst_qprogressdialog.moc" |