Skip to content

Commit 13b6eea

Browse files
committed
core/reloader: null generation ref in reloadables on destruction
On the post-reload reloadable initialzation path, a timer is used to delay reload(). This change fixes a UAF when switching generations while that timer is running.
1 parent 3edb3f4 commit 13b6eea

File tree

2 files changed

+11
-0
lines changed

2 files changed

+11
-0
lines changed

src/core/reload.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ void Reloadable::componentComplete() {
1616
if (this->engineGeneration->reloadComplete) {
1717
// Delayed due to Component.onCompleted running after QQmlParserStatus::componentComplete.
1818
QTimer::singleShot(0, this, &Reloadable::onReloadFinished);
19+
20+
// This only matters for preventing the above timer from UAFing the generation,
21+
// so it isn't connected anywhere else.
22+
QObject::connect(
23+
this->engineGeneration,
24+
&QObject::destroyed,
25+
this,
26+
&Reloadable::onGenerationDestroyed
27+
);
1928
} else {
2029
QObject::connect(
2130
this->engineGeneration,
@@ -43,6 +52,7 @@ void Reloadable::reload(QObject* oldInstance) {
4352
}
4453

4554
void Reloadable::onReloadFinished() { this->reload(nullptr); }
55+
void Reloadable::onGenerationDestroyed() { this->engineGeneration = nullptr; }
4656

4757
void ReloadPropagator::onReload(QObject* oldInstance) {
4858
auto* old = qobject_cast<ReloadPropagator*>(oldInstance);

src/core/reload.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class Reloadable
7171

7272
private slots:
7373
void onReloadFinished();
74+
void onGenerationDestroyed();
7475

7576
protected:
7677
// Called unconditionally in the reload phase, with nullptr if no source could be determined.

0 commit comments

Comments
 (0)