Fix crash in QQuickLoader when source component is garbage collected
It may happen that the QQuickLoader is the last entity left in the system holding a reference to the QQmlComponent *sourceComponent. We have to let the garbage collector know about that by keeping a persistent value for it. Task-number: QTBUG-35334 Change-Id: I715864440378fd9dd4f2d5ef8ff2f171c81ed7ef Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
parent
433949df18
commit
adaedcb9ea
|
@ -106,6 +106,7 @@ void QQuickLoaderPrivate::clear()
|
||||||
component->deleteLater();
|
component->deleteLater();
|
||||||
component = 0;
|
component = 0;
|
||||||
}
|
}
|
||||||
|
componentStrongReference.clear();
|
||||||
source = QUrl();
|
source = QUrl();
|
||||||
|
|
||||||
if (item) {
|
if (item) {
|
||||||
|
@ -472,6 +473,10 @@ void QQuickLoader::setSourceComponent(QQmlComponent *comp)
|
||||||
d->clear();
|
d->clear();
|
||||||
|
|
||||||
d->component = comp;
|
d->component = comp;
|
||||||
|
if (comp) {
|
||||||
|
if (QQmlData *ddata = QQmlData::get(comp))
|
||||||
|
d->componentStrongReference = ddata->jsWrapper.value();
|
||||||
|
}
|
||||||
d->loadingFromSource = false;
|
d->loadingFromSource = false;
|
||||||
|
|
||||||
if (d->active)
|
if (d->active)
|
||||||
|
|
|
@ -106,6 +106,7 @@ public:
|
||||||
QQuickItem *item;
|
QQuickItem *item;
|
||||||
QObject *object;
|
QObject *object;
|
||||||
QQmlComponent *component;
|
QQmlComponent *component;
|
||||||
|
QV4::PersistentValue componentStrongReference; // To ensure GC doesn't delete components created by Qt.createComponent
|
||||||
QQmlContext *itemContext;
|
QQmlContext *itemContext;
|
||||||
QQuickLoaderIncubator *incubator;
|
QQuickLoaderIncubator *incubator;
|
||||||
QV4::PersistentValue initialPropertyValues;
|
QV4::PersistentValue initialPropertyValues;
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
import QtQml 2.0
|
||||||
|
QtObject {}
|
|
@ -0,0 +1,8 @@
|
||||||
|
import QtQuick 2.0
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
active: false
|
||||||
|
function setSourceComponent() {
|
||||||
|
sourceComponent = Qt.createComponent("SimpleTestComponent.qml");
|
||||||
|
}
|
||||||
|
}
|
|
@ -128,6 +128,8 @@ private slots:
|
||||||
void sizeBound();
|
void sizeBound();
|
||||||
void QTBUG_30183();
|
void QTBUG_30183();
|
||||||
|
|
||||||
|
void sourceComponentGarbageCollection();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QQmlEngine engine;
|
QQmlEngine engine;
|
||||||
};
|
};
|
||||||
|
@ -1144,6 +1146,26 @@ void tst_QQuickLoader::QTBUG_30183()
|
||||||
delete loader;
|
delete loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QQuickLoader::sourceComponentGarbageCollection()
|
||||||
|
{
|
||||||
|
QQmlComponent component(&engine, testFileUrl("sourceComponentGarbageCollection.qml"));
|
||||||
|
QScopedPointer<QObject> obj(component.create());
|
||||||
|
QVERIFY(!obj.isNull());
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(obj.data(), "setSourceComponent");
|
||||||
|
engine.collectGarbage();
|
||||||
|
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
|
||||||
|
|
||||||
|
QSignalSpy spy(obj.data(), SIGNAL(loaded()));
|
||||||
|
|
||||||
|
obj->setProperty("active", true);
|
||||||
|
|
||||||
|
if (spy.isEmpty())
|
||||||
|
QVERIFY(spy.wait());
|
||||||
|
|
||||||
|
QCOMPARE(spy.count(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_QQuickLoader)
|
QTEST_MAIN(tst_QQuickLoader)
|
||||||
|
|
||||||
#include "tst_qquickloader.moc"
|
#include "tst_qquickloader.moc"
|
||||||
|
|
Loading…
Reference in New Issue