aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-12-05 16:21:03 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-12-06 15:18:47 +0100
commitadaedcb9ead1c536ff3d8fba0fb9f4fc262d4d45 (patch)
tree7d798f62b3ad61a038468e4e418899388966f968
parent433949df18625e5a04d8e83908ee51f703380f21 (diff)
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>
-rw-r--r--src/quick/items/qquickloader.cpp5
-rw-r--r--src/quick/items/qquickloader_p_p.h1
-rw-r--r--tests/auto/quick/qquickloader/data/SimpleTestComponent.qml2
-rw-r--r--tests/auto/quick/qquickloader/data/sourceComponentGarbageCollection.qml8
-rw-r--r--tests/auto/quick/qquickloader/tst_qquickloader.cpp22
5 files changed, 38 insertions, 0 deletions
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index 7d04be2393..b83c21428c 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -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)
diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h
index 9c94b4ce38..32c271222d 100644
--- a/src/quick/items/qquickloader_p_p.h
+++ b/src/quick/items/qquickloader_p_p.h
@@ -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;
diff --git a/tests/auto/quick/qquickloader/data/SimpleTestComponent.qml b/tests/auto/quick/qquickloader/data/SimpleTestComponent.qml
new file mode 100644
index 0000000000..0e69012662
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/SimpleTestComponent.qml
@@ -0,0 +1,2 @@
+import QtQml 2.0
+QtObject {}
diff --git a/tests/auto/quick/qquickloader/data/sourceComponentGarbageCollection.qml b/tests/auto/quick/qquickloader/data/sourceComponentGarbageCollection.qml
new file mode 100644
index 0000000000..ab86883af5
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/sourceComponentGarbageCollection.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+Loader {
+ active: false
+ function setSourceComponent() {
+ sourceComponent = Qt.createComponent("SimpleTestComponent.qml");
+ }
+}
diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
index 50ded4d95a..1e23d689ff 100644
--- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp
+++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
@@ -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"