From 4594680eb4ba89a69f6a830174028b6e3d14ccfa Mon Sep 17 00:00:00 2001 From: bbedward Date: Mon, 21 Sep 2026 13:20:41 -0400 Subject: [PATCH] core/generation: destroy the engine after the root's children --- changelog/next.md | 1 + src/core/generation.cpp | 42 ++++++++++++++++++++++++++--------------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/changelog/next.md b/changelog/next.md index d3cf529..1b5e633 100644 --- a/changelog/next.md +++ b/changelog/next.md @@ -11,3 +11,4 @@ - Fixed `WlSessionLockSurface.screen` being null and never updating with a real screen on monitor plug. - Fixed `NotificationAction.text` not accepting text updates. - Fixed PipeWire route volume writes for devices without a reported volume step. +- Fixed a crash when quitting or reloading while a `Loader` was still loading asynchronously. diff --git a/src/core/generation.cpp b/src/core/generation.cpp index 9f2c860..ad5dca2 100644 --- a/src/core/generation.cpp +++ b/src/core/generation.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -83,25 +84,36 @@ void EngineGeneration::destroy() { } if (this->root != nullptr) { + // prevent further js execution during teardown of the root's children, gc and the engine. QObject::connect(this->root, &QObject::destroyed, this, [this]() { - // prevent further js execution between garbage collection and engine destruction. this->engine->setInterrupted(true); - - g_generations.remove(this->engine); - - // Garbage is not collected during engine destruction. - this->engine->collectGarbage(); - - delete this->engine; - this->engine = nullptr; - - auto terminate = this->shouldTerminate; - auto code = this->exitCode; - delete this; - - if (terminate) QCoreApplication::exit(code); }); + // QObject::destroyed is emitted before the root's children are destroyed. + // The engine must outlive them, as objects such as Loaders with in-flight + // incubations access it in their destructors. + QObject::connect( + this->root, + &QObject::destroyed, + this, + [this]() { + g_generations.remove(this->engine); + + // Garbage is not collected during engine destruction. + this->engine->collectGarbage(); + + delete this->engine; + this->engine = nullptr; + + auto terminate = this->shouldTerminate; + auto code = this->exitCode; + delete this; + + if (terminate) QCoreApplication::exit(code); + }, + Qt::QueuedConnection + ); + this->root->deleteLater(); this->root = nullptr; } else {