aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabian Kosmale <[email protected]>2025-05-02 09:50:37 +0200
committerFabian Kosmale <[email protected]>2025-05-02 16:02:32 +0200
commit3c347cc0a1f1a514a8b849ecbad5cab31bdd00b3 (patch)
tree7e3acc76a4e84dd1210dba4852033a32188ca8c7
parent4f57e20f254d40081b56a174c4fdae16a1fcfb07 (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.cpp18
-rw-r--r--tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp49
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()