diff options
author | Fabian Kosmale <[email protected]> | 2025-05-02 09:50:37 +0200 |
---|---|---|
committer | Fabian Kosmale <[email protected]> | 2025-05-02 16:02:32 +0200 |
commit | 3c347cc0a1f1a514a8b849ecbad5cab31bdd00b3 (patch) | |
tree | 7e3acc76a4e84dd1210dba4852033a32188ca8c7 | |
parent | 4f57e20f254d40081b56a174c4fdae16a1fcfb07 (diff) |
QQmlComponent::loadFromModule: Fix crash with dynamic metaobjects
If an object has a dynamic meta-object (e.g. because it has been
extended with additional enums), we can no longer create a property
cache.
This could have caused a null-poninter dereference; avoid this by
checking for nullptr.
We currently don't do any checks at all in that case; finding a better
solution is tracked in QTBUG-136560.
Pick-to: 6.9 6.8
Change-Id: I678cf9908d5bbec50e133a462f7f4c813dca44dd
Reviewed-by: Ulf Hermann <[email protected]>
-rw-r--r-- | src/qml/qml/qqmlcomponent.cpp | 18 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp | 49 |
2 files changed, 61 insertions, 6 deletions
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index c4e0ea1b2b..803521fa63 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1140,13 +1140,19 @@ QObject *QQmlComponentPrivate::beginCreate(QQmlRefPointer<QQmlContextData> conte m_state.ensureRequiredPropertyStorage(rv); } - for (int i = 0, propertyCount = propertyCache->propertyCount(); i < propertyCount; ++i) { - if (const QQmlPropertyData *propertyData = propertyCache->property(i); propertyData->isRequired()) { - m_state.ensureRequiredPropertyStorage(rv); - RequiredPropertyInfo info; - info.propertyName = propertyData->name(rv); - m_state.addPendingRequiredProperty(rv, propertyData, info); + if (propertyCache) { + for (int i = 0, propertyCount = propertyCache->propertyCount(); i < propertyCount; ++i) { + if (const QQmlPropertyData *propertyData = propertyCache->property(i); propertyData->isRequired()) { + m_state.ensureRequiredPropertyStorage(rv); + RequiredPropertyInfo info; + info.propertyName = propertyData->name(rv); + m_state.addPendingRequiredProperty(rv, propertyData, info); + } } + } else { + // we couldn't get a propertyCache from ensurePropertyCache + // it is unclear what we can do in that case + // ### TOOD: QTBUG-136560 } } diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp index f6869ab300..d14e0b76a4 100644 --- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp +++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp @@ -1563,11 +1563,53 @@ struct SingleRequiredProperty : QObject int i = 42; }; + +struct SingleRequiredPropertyDynamic : QObject +{ + Q_OBJECT + Q_PROPERTY(int i MEMBER i REQUIRED) + + int i = 42; + + class QObjectDynamicMetaObject : public QDynamicMetaObjectData + { + public: + #if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) + const QMetaObject *toDynamicMetaObject(QObject *) const final + { + return &SingleRequiredPropertyDynamic::staticMetaObject; + } + #else + QMetaObject *toDynamicMetaObject(QObject *) final + { + return const_cast<QMetaObject *>(&SingleRequiredPropertyDynamic::staticMetaObject); + } + #endif + int metaCall(QObject *o, QMetaObject::Call c, int id, void **argv) final + { + return o->qt_metacall(c, id, argv); + } + }; + +public: + SingleRequiredPropertyDynamic() { + auto priv = QObjectPrivate::get(this); + priv->metaObject = new QObjectDynamicMetaObject; + } + + ~SingleRequiredPropertyDynamic() { + auto priv = QObjectPrivate::get(this); + delete priv->metaObject; + priv->metaObject = nullptr ; + } +}; + void tst_qqmlcomponent::loadFromModuleRequired() { QQmlEngine engine; qmlRegisterType<SingleRequiredProperty>("qqmlcomponenttest", 1, 0, "SingleRequiredProperty"); + qmlRegisterType<SingleRequiredPropertyDynamic>("qqmlcomponenttest", 1, 0, "SingleRequiredPropertyDynamic"); const QString error = QStringLiteral("Required property i was not initialized"); { QQmlComponent component(&engine, "qqmlcomponenttest", "SingleRequiredProperty"); @@ -1591,6 +1633,13 @@ void tst_qqmlcomponent::loadFromModuleRequired() QVERIFY(component.isError()); QCOMPARE(component.errorString(), qPrintable(":-1 " + error + "\n")); } + { + QQmlComponent component(&engine, "qqmlcomponenttest", "SingleRequiredPropertyDynamic"); + QVERIFY2(!component.isError(), qPrintable(component.errorString())); + QScopedPointer<QObject> root(component.create()); + QEXPECT_FAIL("", "Can't check required properties when there's a dynamic metaobject", Continue); + QVERIFY(!root); + } } void tst_qqmlcomponent::loadUrlRequired() |