diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-01-10 15:22:20 +0100 |
---|---|---|
committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-01-13 13:27:36 +0100 |
commit | e5570eecd3a4fc61020d28699169707a2c1f5dc9 (patch) | |
tree | d98f9b1ac19acbcb50b2194377c798304e958272 | |
parent | 517c374375c8b989f17a52aacbd9d5891469cba2 (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.cpp | 16 | ||||
-rw-r--r-- | src/qml/qml/qqmlvmemetaobject_p.h | 2 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/data/listContainingDeleted.qml | 36 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 21 |
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" |