From ef0e13257ddd57c967000213e3c9812b3c08da91 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Tue, 1 Mar 2022 11:25:11 +0100 Subject: [PATCH] QMetaObjectBuilder: Always set Data::metatypes The array of metatypes should always contain at least one entry (for the metatype of the current metaobject itself). This prevents crashes in the case of a metaobject without meta-methods and properties (as observed in Qt for Python). Pick-to: 6.2 6.3 Change-Id: I7a6fb316eea48c4852b6f1c26e0a930aeba4c799 Reviewed-by: Friedemann Kleint --- src/corelib/kernel/qmetaobjectbuilder.cpp | 56 +++++++++---------- .../tst_qmetaobjectbuilder.cpp | 12 ++++ 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp index 4f762b5e96..931dcfe2fd 100644 --- a/src/corelib/kernel/qmetaobjectbuilder.cpp +++ b/src/corelib/kernel/qmetaobjectbuilder.cpp @@ -1439,41 +1439,39 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf, size += sizeof(SuperData) * (d->relatedMetaObjects.size() + 1); } - if (d->properties.size() > 0 || d->methods.size() > 0 || d->constructors.size() > 0) { - ALIGN(size, QtPrivate::QMetaTypeInterface *); - auto types = reinterpret_cast(buf + size); - if constexpr (mode == Construct) { - meta->d.metaTypes = types; - for (const auto &prop : d->properties) { - QMetaType mt = prop.metaType; - *types = reinterpret_cast(mt); - types++; - } - // add metatype interface for this metaobject - must be null - // as we can't know our metatype - *types = nullptr; + ALIGN(size, QtPrivate::QMetaTypeInterface *); + auto types = reinterpret_cast(buf + size); + if constexpr (mode == Construct) { + meta->d.metaTypes = types; + for (const auto &prop : d->properties) { + QMetaType mt = prop.metaType; + *types = reinterpret_cast(mt); types++; - for (const auto &method: d->methods) { - QMetaType mt(QMetaType::fromName(method.returnType).id()); + } + // add metatype interface for this metaobject - must be null + // as we can't know our metatype + *types = nullptr; + types++; + for (const auto &method: d->methods) { + QMetaType mt(QMetaType::fromName(method.returnType).id()); + *types = reinterpret_cast(mt); + types++; + for (const auto ¶meterType: method.parameterTypes()) { + QMetaType mt = QMetaType::fromName(parameterType); + *types = reinterpret_cast(mt); + types++; + } + } + for (const auto &constructor : d->constructors) { + for (const auto ¶meterType : constructor.parameterTypes()) { + QMetaType mt = QMetaType::fromName(parameterType); *types = reinterpret_cast(mt); types++; - for (const auto ¶meterType: method.parameterTypes()) { - QMetaType mt = QMetaType::fromName(parameterType); - *types = reinterpret_cast(mt); - types++; - } - } - for (const auto &constructor : d->constructors) { - for (const auto ¶meterType : constructor.parameterTypes()) { - QMetaType mt = QMetaType::fromName(parameterType); - *types = reinterpret_cast(mt); - types++; - } } } - // parameterMetaTypesIndex is equal to the total number of metatypes - size += sizeof(QMetaType) * parameterMetaTypesIndex; } + // parameterMetaTypesIndex is equal to the total number of metatypes + size += sizeof(QMetaType) * parameterMetaTypesIndex; // Align the final size and return it. ALIGN(size, void *); diff --git a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp index 188a5a6626..9e96d0e02c 100644 --- a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp +++ b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp @@ -67,6 +67,8 @@ private slots: void cleanupTestCase(); + void ownMetaTypeNoProperties(); + private: static bool checkForSideEffects (const QMetaObjectBuilder& builder, @@ -1657,6 +1659,16 @@ void tst_QMetaObjectBuilder::propertyMetaType() free(mo); } +void tst_QMetaObjectBuilder::ownMetaTypeNoProperties() +{ + QMetaObjectBuilder builder; + builder.setClassName("NoProperties"); + auto mo = builder.toMetaObject(); + auto cleanup = qScopeGuard([&](){ free(mo); }); + // own metatype should be invalid, as the dynamic metaobject has not been registered + QVERIFY(!mo->metaType().isValid());// should not crash +} + void tst_QMetaObjectBuilder::cleanupTestCase() { for (QMetaObject *obj: dynamicMetaObjectsPendingFree)