Skip to content

Commit 49a3752

Browse files
committed
core: correctly deregister QML incubators on destruction
Previously we'd try to cast the QObject* sender from QObject::destroyed to a QQmlIncubationController*. This will always return nullptr because C++ destructors change the type of the object and the QQmlIncubationController destructor has already run at this point. We now store controllers as QObject*s. Fixes #108
1 parent 026aac3 commit 49a3752

File tree

2 files changed

+30
-34
lines changed

2 files changed

+30
-34
lines changed

src/core/generation.cpp

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <qlist.h>
1212
#include <qlogging.h>
1313
#include <qloggingcategory.h>
14+
#include <qnamespace.h>
1415
#include <qobject.h>
1516
#include <qqmlcontext.h>
1617
#include <qqmlengine.h>
@@ -238,23 +239,24 @@ void EngineGeneration::onDirectoryChanged() {
238239
void EngineGeneration::registerIncubationController(QQmlIncubationController* controller) {
239240
// We only want controllers that we can swap out if destroyed.
240241
// This happens if the window owning the active controller dies.
241-
if (auto* obj = dynamic_cast<QObject*>(controller)) {
242-
QObject::connect(
243-
obj,
244-
&QObject::destroyed,
245-
this,
246-
&EngineGeneration::incubationControllerDestroyed
247-
);
248-
} else {
242+
auto* obj = dynamic_cast<QObject*>(controller);
243+
if (!obj) {
249244
qCWarning(logIncubator) << "Could not register incubation controller as it is not a QObject"
250245
<< controller;
251246

252247
return;
253248
}
254249

255-
this->incubationControllers.push_back(controller);
256-
qCDebug(logIncubator) << "Registered incubation controller" << controller << "to generation"
257-
<< this;
250+
QObject::connect(
251+
obj,
252+
&QObject::destroyed,
253+
this,
254+
&EngineGeneration::incubationControllerDestroyed,
255+
Qt::UniqueConnection
256+
);
257+
258+
this->incubationControllers.push_back(obj);
259+
qCDebug(logIncubator) << "Registered incubation controller" << obj << "to generation" << this;
258260

259261
// This function can run during destruction.
260262
if (this->engine == nullptr) return;
@@ -264,21 +266,25 @@ void EngineGeneration::registerIncubationController(QQmlIncubationController* co
264266
}
265267
}
266268

269+
// Multiple controllers may be destroyed at once. Dynamic casts must be performed before working
270+
// with any controllers. The QQmlIncubationController destructor will already have run by the
271+
// point QObject::destroyed is called, so we can't cast to that.
267272
void EngineGeneration::deregisterIncubationController(QQmlIncubationController* controller) {
268-
if (auto* obj = dynamic_cast<QObject*>(controller)) {
269-
QObject::disconnect(obj, nullptr, this, nullptr);
270-
} else {
273+
auto* obj = dynamic_cast<QObject*>(controller);
274+
if (!obj) {
271275
qCCritical(logIncubator) << "Deregistering incubation controller which is not a QObject, "
272276
"however only QObject controllers should be registered.";
273277
}
274278

275-
if (!this->incubationControllers.removeOne(controller)) {
276-
qCCritical(logIncubator) << "Failed to deregister incubation controller" << controller << "from"
279+
QObject::disconnect(obj, nullptr, this, nullptr);
280+
281+
if (this->incubationControllers.removeOne(obj)) {
282+
qCDebug(logIncubator) << "Deregistered incubation controller" << obj << "from" << this;
283+
} else {
284+
qCCritical(logIncubator) << "Failed to deregister incubation controller" << obj << "from"
277285
<< this << "as it was not registered to begin with";
278286
qCCritical(logIncubator) << "Current registered incuabation controllers"
279287
<< this->incubationControllers;
280-
} else {
281-
qCDebug(logIncubator) << "Deregistered incubation controller" << controller << "from" << this;
282288
}
283289

284290
// This function can run during destruction.
@@ -293,22 +299,12 @@ void EngineGeneration::deregisterIncubationController(QQmlIncubationController*
293299

294300
void EngineGeneration::incubationControllerDestroyed() {
295301
auto* sender = this->sender();
296-
auto* controller = dynamic_cast<QQmlIncubationController*>(sender);
297302

298-
if (controller == nullptr) {
299-
qCCritical(logIncubator) << "Destroyed incubation controller" << sender << "is not known to"
300-
<< this << ", this may cause memory corruption";
301-
qCCritical(logIncubator) << "Current registered incuabation controllers"
302-
<< this->incubationControllers;
303-
304-
return;
305-
}
306-
307-
if (this->incubationControllers.removeOne(controller)) {
308-
qCDebug(logIncubator) << "Destroyed incubation controller" << controller << "deregistered from"
303+
if (this->incubationControllers.removeAll(sender) != 0) {
304+
qCDebug(logIncubator) << "Destroyed incubation controller" << sender << "deregistered from"
309305
<< this;
310306
} else {
311-
qCCritical(logIncubator) << "Destroyed incubation controller" << controller
307+
qCCritical(logIncubator) << "Destroyed incubation controller" << sender
312308
<< "was not registered, but its destruction was observed by" << this;
313309

314310
return;
@@ -317,7 +313,7 @@ void EngineGeneration::incubationControllerDestroyed() {
317313
// This function can run during destruction.
318314
if (this->engine == nullptr) return;
319315

320-
if (this->engine->incubationController() == controller) {
316+
if (dynamic_cast<QObject*>(this->engine->incubationController()) == sender) {
321317
qCDebug(logIncubator
322318
) << "Destroyed incubation controller was currently active, reassigning from pool";
323319
this->assignIncubationController();
@@ -371,7 +367,7 @@ void EngineGeneration::assignIncubationController() {
371367
if (this->incubationControllersLocked || this->incubationControllers.isEmpty()) {
372368
controller = &this->delayedIncubationController;
373369
} else {
374-
controller = this->incubationControllers.first();
370+
controller = dynamic_cast<QQmlIncubationController*>(this->incubationControllers.first());
375371
}
376372

377373
qCDebug(logIncubator) << "Assigning incubation controller" << controller << "to generation"

src/core/generation.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ private slots:
8989
private:
9090
void postReload();
9191
void assignIncubationController();
92-
QVector<QQmlIncubationController*> incubationControllers;
92+
QVector<QObject*> incubationControllers;
9393
bool incubationControllersLocked = false;
9494
QHash<const void*, EngineGenerationExt*> extensions;
9595

0 commit comments

Comments
 (0)