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:
Simon Hausmann 2013-12-05 16:21:03 +01:00 committed by The Qt Project
parent 433949df18
commit adaedcb9ea
5 changed files with 38 additions and 0 deletions

View File

@ -106,6 +106,7 @@ void QQuickLoaderPrivate::clear()
component->deleteLater();
component = 0;
}
componentStrongReference.clear();
source = QUrl();
if (item) {
@ -472,6 +473,10 @@ void QQuickLoader::setSourceComponent(QQmlComponent *comp)
d->clear();
d->component = comp;
if (comp) {
if (QQmlData *ddata = QQmlData::get(comp))
d->componentStrongReference = ddata->jsWrapper.value();
}
d->loadingFromSource = false;
if (d->active)

View File

@ -106,6 +106,7 @@ public:
QQuickItem *item;
QObject *object;
QQmlComponent *component;
QV4::PersistentValue componentStrongReference; // To ensure GC doesn't delete components created by Qt.createComponent
QQmlContext *itemContext;
QQuickLoaderIncubator *incubator;
QV4::PersistentValue initialPropertyValues;

View File

@ -0,0 +1,2 @@
import QtQml 2.0
QtObject {}

View File

@ -0,0 +1,8 @@
import QtQuick 2.0
Loader {
active: false
function setSourceComponent() {
sourceComponent = Qt.createComponent("SimpleTestComponent.qml");
}
}

View File

@ -128,6 +128,8 @@ private slots:
void sizeBound();
void QTBUG_30183();
void sourceComponentGarbageCollection();
private:
QQmlEngine engine;
};
@ -1144,6 +1146,26 @@ void tst_QQuickLoader::QTBUG_30183()
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)
#include "tst_qquickloader.moc"