Skip to content

Commit d5a72d8

Browse files
committed
fix: prevent potential QFutureWatcher race conditions
1 parent bb90767 commit d5a72d8

File tree

5 files changed

+30
-11
lines changed

5 files changed

+30
-11
lines changed

src/hobbits-core/abstractpluginrunner.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,16 @@ class Q_DECL_EXPORT AbstractPluginRunner : public AbstractPluginRunnerQObject
8080
m_actionWatcher = QSharedPointer<PluginActionWatcher<QSharedPointer<T>>>(
8181
new PluginActionWatcher<QSharedPointer<T>>(
8282
future,
83-
progress));
83+
progress,
84+
true));
8485

8586
connect(m_actionWatcher->watcher(), SIGNAL(finished()), this, SLOT(postProcess()));
8687
connect(m_actionWatcher->progress().data(), &PluginActionProgress::progressPercentChanged, [this](int prog) {
8788
this->progress(m_id, prog);
8889
});
8990

91+
m_actionWatcher->setFutureInWatcher();
92+
9093
return m_actionWatcher;
9194
}
9295

src/hobbits-core/pluginactionwatcher.h

+12-2
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,15 @@ template<class T>
1515
class Q_DECL_EXPORT PluginActionWatcher
1616
{
1717
public:
18-
explicit PluginActionWatcher(QFuture<T> future, QSharedPointer<PluginActionProgress> progress) :
18+
explicit PluginActionWatcher(QFuture<T> future,
19+
QSharedPointer<PluginActionProgress> progress,
20+
bool delayWatcherSet = false) :
1921
m_progress(progress)
2022
{
2123
m_future = future;
22-
m_futureWatcher.setFuture(future);
24+
if (!delayWatcherSet) {
25+
m_futureWatcher.setFuture(future);
26+
}
2327
}
2428

2529
T result()
@@ -37,6 +41,12 @@ class Q_DECL_EXPORT PluginActionWatcher
3741
return &m_futureWatcher;
3842
}
3943

44+
/// If the watcher set was delayed to allow for race-safe connections, it can be set with this method
45+
void setFutureInWatcher()
46+
{
47+
m_futureWatcher.setFuture(m_future);
48+
}
49+
4050
private:
4151
QFuture<T> m_future;
4252
QFutureWatcher<T> m_futureWatcher;

src/hobbits-widgets/displaywidget.cpp

+9-6
Original file line numberDiff line numberDiff line change
@@ -161,13 +161,16 @@ void DisplayWidget::performDisplayRender()
161161
this->size(),
162162
m_displayParameters,
163163
m_displayRenderProgress);
164-
connect(&m_displayRenderWatcher, &QFutureWatcher<QImage>::finished, this, [this]() {
165-
if (this->m_displayRenderWatcher.isFinished()) {
166-
this->setDisplayResult(this->m_displayRenderWatcher.result());
164+
165+
m_displayRenderWatcher = QSharedPointer<QFutureWatcher<QSharedPointer<DisplayResult>>>(new QFutureWatcher<QSharedPointer<DisplayResult>>());
166+
167+
connect(m_displayRenderWatcher.data(), &QFutureWatcher<QImage>::finished, this, [this]() {
168+
if (this->m_displayRenderWatcher->isFinished()) {
169+
this->setDisplayResult(this->m_displayRenderWatcher->result());
167170
}
168171
});
169172

170-
m_displayRenderWatcher.setFuture(future);
173+
m_displayRenderWatcher->setFuture(future);
171174
}
172175
else {
173176
m_displayResult = m_display->renderDisplay(this->size(), m_displayParameters, QSharedPointer<PluginActionProgress>());
@@ -196,8 +199,8 @@ void DisplayWidget::resetRendering()
196199
m_displayRenderProgress->setCancelled(true);
197200
disconnect(m_displayRenderProgress.data(), SIGNAL(progressUpdate(QString, QVariant)), this, SLOT(handleDisplayRenderPreview(QString, QVariant)));
198201
}
199-
if (m_displayRenderWatcher.isRunning()) {
200-
m_displayRenderWatcher.cancel();
202+
if (!m_displayRenderWatcher.isNull() && m_displayRenderWatcher->isRunning()) {
203+
m_displayRenderWatcher->cancel();
201204
}
202205
}
203206

src/hobbits-widgets/displaywidget.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ private slots:
6565
bool m_repaintScheduled;
6666
QMutex m_mutex;
6767

68-
QFutureWatcher<QSharedPointer<DisplayResult>> m_displayRenderWatcher;
68+
QSharedPointer<QFutureWatcher<QSharedPointer<DisplayResult>>> m_displayRenderWatcher;
6969
QSharedPointer<PluginActionProgress> m_displayRenderProgress;
7070
};
7171

src/hobbits-widgets/previewscrollbar.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ void PreviewScrollBar::paintEvent(QPaintEvent *event)
5151
container, progress);
5252

5353
auto actionWatcher = QSharedPointer<PluginActionWatcher<QImage>>(
54-
new PluginActionWatcher<QImage>(future, progress));
54+
new PluginActionWatcher<QImage>(future, progress, true));
5555
m_renderWatchers.insert(containerPtr, actionWatcher);
5656

5757
auto watcherRef = QWeakPointer<PluginActionWatcher<QImage>>(actionWatcher);
@@ -93,6 +93,9 @@ void PreviewScrollBar::paintEvent(QPaintEvent *event)
9393
this->update();
9494
});
9595

96+
// set the future in the watcher now that the connections are done
97+
actionWatcher->setFutureInWatcher();
98+
9699
// clean out any deleted containers
97100
m_weakRefMap.insert(containerPtr, QWeakPointer<BitContainer>(container));
98101
for (quint64 key : m_weakRefMap.keys()) {

0 commit comments

Comments
 (0)