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.
This commit is contained in:
outfoxxed 2024-08-30 16:23:32 -07:00
parent 3edb3f4efa
commit 13b6eeaa22
Signed by: outfoxxed
GPG key ID: 4C88A185FB89301E
2 changed files with 11 additions and 0 deletions

View file

@ -16,6 +16,15 @@ void Reloadable::componentComplete() {
if (this->engineGeneration->reloadComplete) {
// Delayed due to Component.onCompleted running after QQmlParserStatus::componentComplete.
QTimer::singleShot(0, this, &Reloadable::onReloadFinished);
// This only matters for preventing the above timer from UAFing the generation,
// so it isn't connected anywhere else.
QObject::connect(
this->engineGeneration,
&QObject::destroyed,
this,
&Reloadable::onGenerationDestroyed
);
} else {
QObject::connect(
this->engineGeneration,
@ -43,6 +52,7 @@ void Reloadable::reload(QObject* oldInstance) {
}
void Reloadable::onReloadFinished() { this->reload(nullptr); }
void Reloadable::onGenerationDestroyed() { this->engineGeneration = nullptr; }
void ReloadPropagator::onReload(QObject* oldInstance) {
auto* old = qobject_cast<ReloadPropagator*>(oldInstance);

View file

@ -71,6 +71,7 @@ public:
private slots:
void onReloadFinished();
void onGenerationDestroyed();
protected:
// Called unconditionally in the reload phase, with nullptr if no source could be determined.