aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/quick/qquickrepeater
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2014-06-24 16:09:29 +0200
committerSimon Hausmann <simon.hausmann@digia.com>2014-06-24 17:09:35 +0200
commit9f22767784dc859283b321c47636ea708eef3bfe (patch)
treee47f68fb1943d913c124da2c48f0195e38345649 /tests/auto/quick/qquickrepeater
parentcf93acbee66db96a6f7fab8607432b70ec5c0437 (diff)
Fix crash in QQmlDelegateModel during destruction phase
It has been reported multiple times (with different back traces) that the QQmlDelegateModel tries to access a dangling QQmlContext pointer. The scenarios for reaching this point differ slightly, one such scenario is very late model activity during the scene destruction. The provided test-case simulates that and the provided patch guards the QQmlContext in a QPointer. Task-number: QTBUG-39780 Change-Id: I594ee4918cd1b78c5db5c164314e85e9eea99fbd Reviewed-by: Alan Alpert (Personal) <416365416c@gmail.com>
Diffstat (limited to 'tests/auto/quick/qquickrepeater')
-rw-r--r--tests/auto/quick/qquickrepeater/data/invalidContextCrash.qml7
-rw-r--r--tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp43
2 files changed, 50 insertions, 0 deletions
diff --git a/tests/auto/quick/qquickrepeater/data/invalidContextCrash.qml b/tests/auto/quick/qquickrepeater/data/invalidContextCrash.qml
new file mode 100644
index 0000000000..4a822cf25a
--- /dev/null
+++ b/tests/auto/quick/qquickrepeater/data/invalidContextCrash.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+Item {
+ Repeater {
+ model: badModel
+ delegate: Item {}
+ }
+}
diff --git a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp
index 9fb76f9584..2dc5a65d7d 100644
--- a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp
+++ b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp
@@ -79,6 +79,7 @@ private slots:
void initParent();
void dynamicModelCrash();
void visualItemModelCrash();
+ void invalidContextCrash();
};
class TestObject : public QObject
@@ -744,6 +745,48 @@ void tst_QQuickRepeater::visualItemModelCrash()
delete window;
}
+class BadModel : public QAbstractListModel
+{
+public:
+ ~BadModel()
+ {
+ beginResetModel();
+ endResetModel();
+ }
+
+ QVariant data(const QModelIndex &, int) const { return QVariant(); }
+ int rowCount(const QModelIndex &) const { return 0; }
+};
+
+
+void tst_QQuickRepeater::invalidContextCrash()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("invalidContextCrash.qml"));
+
+ BadModel* model = new BadModel;
+ engine.rootContext()->setContextProperty("badModel", model);
+
+ QScopedPointer<QObject> root(component.create());
+ QCOMPARE(root->children().count(), 1);
+ QObject *repeater = root->children().first();
+
+ // Make sure the model comes first in the child list, so it will be
+ // deleted first and then the repeater. During deletion the QML context
+ // has been deleted already and is invalid.
+ model->setParent(root.data());
+ repeater->setParent(0);
+ repeater->setParent(root.data());
+
+ QCOMPARE(root->children().count(), 2);
+ QVERIFY(root->children().at(0) == model);
+ QVERIFY(root->children().at(1) == repeater);
+
+ // Delete the root object, which will invalidate/delete the QML context
+ // and then delete the child QObjects, which may try to access the context.
+ root.reset(0);
+}
+
QTEST_MAIN(tst_QQuickRepeater)
#include "tst_qquickrepeater.moc"