aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2020-01-10 15:22:20 +0100
committerFabian Kosmale <fabian.kosmale@qt.io>2020-01-13 13:27:36 +0100
commite5570eecd3a4fc61020d28699169707a2c1f5dc9 (patch)
treed98f9b1ac19acbcb50b2194377c798304e958272
parent517c374375c8b989f17a52aacbd9d5891469cba2 (diff)
QML list property: Avoid crash if contained object is deleted
Task-number: QTBUG-81123 Change-Id: I3dd1a42e444f817722368cd268c2f987a99fbf1c Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp16
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h2
-rw-r--r--tests/auto/qml/qqmllanguage/data/listContainingDeleted.qml36
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp21
4 files changed, 66 insertions, 9 deletions
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index e0ca1ae6c5..eff13ef2c3 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -84,15 +84,15 @@ public:
Q_ASSERT(v);
Q_ASSERT(v->d());
QVariant &data = v->d()->data();
- Q_ASSERT(data.userType() == qMetaTypeId<QList<QObject *>>());
- m_list = static_cast<QList<QObject *> *>(data.data());
+ Q_ASSERT(data.userType() == qMetaTypeId<QVector<QQmlGuard<QObject>>>());
+ m_list = static_cast<QVector<QQmlGuard<QObject>> *>(data.data());
Q_ASSERT(m_list);
}
~ResolvedList() = default;
QQmlVMEMetaObject *metaObject() const { return m_metaObject; }
- QList<QObject *> *list() const { return m_list; }
+ QVector<QQmlGuard<QObject>> *list() const { return m_list; }
quintptr id() const { return m_id; }
void activateSignal() const
@@ -103,7 +103,7 @@ public:
private:
QQmlVMEMetaObject *m_metaObject = nullptr;
- QList<QObject *> *m_list = nullptr;
+ QVector<QQmlGuard<QObject>> *m_list = nullptr;
quintptr m_id = 0;
};
@@ -604,7 +604,7 @@ QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id) const
return wrapper->object();
}
-QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id) const
+QVector<QQmlGuard<QObject>> *QQmlVMEMetaObject::readPropertyAsList(int id) const
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
@@ -612,12 +612,12 @@ QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id) const
QV4::Scope scope(engine);
QV4::Scoped<QV4::VariantObject> v(scope, *(md->data() + id));
- if (!v || (int)v->d()->data().userType() != qMetaTypeId<QList<QObject *> >()) {
- QVariant variant(QVariant::fromValue(QList<QObject*>()));
+ if (!v || (int)v->d()->data().userType() != qMetaTypeId<QVector<QQmlGuard<QObject>> >()) {
+ QVariant variant(QVariant::fromValue(QVector<QQmlGuard<QObject>>()));
v = engine->newVariantObject(variant);
md->set(engine, id, v);
}
- return static_cast<QList<QObject *> *>(v->d()->data().data());
+ return static_cast<QVector<QQmlGuard<QObject>> *>(v->d()->data().data());
}
QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id) const
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index 58332ff7a8..e17701a968 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -188,7 +188,7 @@ public:
QDateTime readPropertyAsDateTime(int id);
QRectF readPropertyAsRectF(int id) const;
QObject *readPropertyAsQObject(int id) const;
- QList<QObject *> *readPropertyAsList(int id) const;
+ QVector<QQmlGuard<QObject> > *readPropertyAsList(int id) const;
void writeProperty(int id, int v);
void writeProperty(int id, bool v);
diff --git a/tests/auto/qml/qqmllanguage/data/listContainingDeleted.qml b/tests/auto/qml/qqmllanguage/data/listContainingDeleted.qml
new file mode 100644
index 0000000000..efd273ddc6
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/listContainingDeleted.qml
@@ -0,0 +1,36 @@
+import QtQuick 2.12
+
+Item {
+ width: 1024
+ height: 800
+
+ property Component a: Component {
+ id: a
+ Item {
+ property list<QtObject> myList: [
+ QtObject {
+ property bool enabled: true
+ }
+ ]
+ }
+ }
+ Component {
+ id: b
+ Item {
+ property list<QtObject> myList
+
+ function test() {
+ for (var i = 0; i < myList.length; ++i)
+ console.log(i, "==", myList[i].enabled)
+ }
+ }
+ }
+ property Item instance
+ function doAssign(o) {
+ instance = b.createObject(null, {myList: o.myList})
+ }
+ function use() {
+ instance.test()
+ }
+
+}
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index c36e707ff8..fca398d7b2 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -309,6 +309,8 @@ private slots:
void selfReference();
void selfReferencingSingleton();
+ void listContainingDeletedObject();
+
private:
QQmlEngine engine;
QStringList defaultImportPathList;
@@ -5354,6 +5356,25 @@ void tst_qqmllanguage::selfReferencingSingleton()
QCOMPARE(singletonPointer->property("dummy").toInt(), 42);
}
+void tst_qqmllanguage::listContainingDeletedObject()
+{
+ QQmlEngine engine;
+ auto url = testFileUrl("listContainingDeleted.qml");
+ const QString message = url.toString() + ":24: TypeError: Cannot read property 'enabled' of null";
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, message.toUtf8().data());
+ QQmlComponent comp(&engine, url);
+ QScopedPointer<QObject> root(comp.create());
+ QVERIFY(root);
+
+ auto cmp = root->property("a").value<QQmlComponent*>();
+ auto o = cmp->create();
+
+ QMetaObject::invokeMethod(root.get(), "doAssign", Q_ARG(QVariant, QVariant::fromValue(o)));
+ delete o;
+ QMetaObject::invokeMethod(root.get(), "use");
+
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"