summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/widgets/dialogs/qprogressdialog.cpp7
-rw-r--r--tests/auto/widgets/dialogs/qprogressdialog/tst_qprogressdialog.cpp24
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"