aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp10
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h2
-rw-r--r--tests/auto/quick/qquickrepeater/data/invalidContextCrash.qml7
-rw-r--r--tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp43
4 files changed, 56 insertions, 6 deletions
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index 4591d42710..f7ce1c8fad 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -903,7 +903,7 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, bo
if (!m_delegate || index < 0 || index >= m_compositor.count(group)) {
qWarning() << "DelegateModel::item: index out range" << index << m_compositor.count(group);
return 0;
- } else if (!m_context->isValid()) {
+ } else if (!m_context || !m_context->isValid()) {
return 0;
}
@@ -946,7 +946,7 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, bo
cacheItem->incubationTask->index[i] = it.index[i];
QQmlContextData *ctxt = new QQmlContextData;
- ctxt->setParent(QQmlContextData::get(creationContext ? creationContext : m_context));
+ ctxt->setParent(QQmlContextData::get(creationContext ? creationContext : m_context.data()));
ctxt->contextObject = cacheItem;
cacheItem->contextData = ctxt;
@@ -1409,7 +1409,7 @@ void QQmlDelegateModelPrivate::emitModelUpdated(const QQmlChangeSet &changeSet,
void QQmlDelegateModelPrivate::emitChanges()
{
- if (m_transaction || !m_complete || !m_context->isValid())
+ if (m_transaction || !m_complete || !m_context || !m_context->isValid())
return;
m_transaction = true;
@@ -1594,7 +1594,7 @@ QQmlDelegateModelAttached *QQmlDelegateModel::qmlAttachedProperties(QObject *obj
bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const QV4::ValueRef object, int groups)
{
- if (!m_context->isValid())
+ if (!m_context || !m_context->isValid())
return false;
QQmlDelegateModelItem *cacheItem = m_adaptorModel.createItem(m_cacheMetaType, m_context->engine(), -1);
@@ -2433,7 +2433,7 @@ QQmlV4Handle QQmlDelegateModelGroup::get(int index)
return QQmlV4Handle(QV4::Encode::undefined());
QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
- if (!model->m_context->isValid()) {
+ if (!model->m_context || !model->m_context->isValid()) {
return QQmlV4Handle(QV4::Encode::undefined());
} else if (index < 0 || index >= model->m_compositor.count(d->group)) {
qmlInfo(this) << tr("get: index out of range");
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index d64f641a1b..cf7a719455 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -303,7 +303,7 @@ public:
QQmlListCompositor m_compositor;
QQmlComponent *m_delegate;
QQmlDelegateModelItemMetaType *m_cacheMetaType;
- QQmlContext *m_context;
+ QPointer<QQmlContext> m_context;
QQmlDelegateModelParts *m_parts;
QQmlDelegateModelGroupEmitterList m_pendingParts;
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"