summaryrefslogtreecommitdiffstats
path: root/src/widgets/dialogs
diff options
context:
space:
mode:
authorChristian Heimlich <chris@pcserenity.com>2020-09-19 05:53:26 -0400
committerChristian Heimlich <chris@pcserenity.com>2020-09-21 03:19:55 -0400
commit10bc093d4fa1889b7a5f6151c9bcc79aa31ecfc5 (patch)
tree245187c0b9ad23103172e92b9ac53b5523d496c4 /src/widgets/dialogs
parent169f332eab5dc047112e9db11556d0757a86b400 (diff)
Add reentrancy guard for processEvents() in QProgressDialog::setValue()
Current implementation of QProgressDialog always calls QCoreApplication::processEvents() when the user calls QProgressDialog::setValue() if the PD is modal. For most cases this is fine, but when using a Qt::WindowModal PD with setValue() connected to a signal in another thread using Qt::QueuedConnection a reentrancy issue is present if setValue() is triggered too frequently as the execution of its previous call may not have finished. If this happens too many times in a row a stack overflow will occur. Current documentation notes this potential issue but offers no way it avoid it while still using QProgressDialog (user must implement a custom dialog) without resorting to using Qt::BlockingQueuedConnection, which unnecessarily reduces performance. Introduces the boolean reentrancy guard "processingEvents" that is checked before calling QCoreApplication::processEvents() in a modal PD when setValue() is used. It is set before the first call to processEvents() and cleared after that call returns. This ensures that only one invocation of processEvents() is possible from within setValue() at a time, and thereby minimizes iterations of the main event loop and eliminates the aforementioned stack overflow condition. See - https://forum.qt.io/topic/118292/ Fixes: QTBUG-10561 Pick-to: 5.15 Change-Id: Ifa9b91cbb66881981356954ead0906bdc91fab60 Reviewed-by: Samuel Gaist <samuel.gaist@idiap.ch>
Diffstat (limited to 'src/widgets/dialogs')
-rw-r--r--src/widgets/dialogs/qprogressdialog.cpp7
1 files changed, 6 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();