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 <Friedemann.Kleint@qt.io>
bb10
Fabian Kosmale 2022-03-01 11:25:11 +01:00
parent 9d4e6d560a
commit ef0e13257d
2 changed files with 39 additions and 29 deletions

View File

@ -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<QtPrivate::QMetaTypeInterface **>(buf + size);
if constexpr (mode == Construct) {
meta->d.metaTypes = types;
for (const auto &prop : d->properties) {
QMetaType mt = prop.metaType;
*types = reinterpret_cast<QtPrivate::QMetaTypeInterface *&>(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<QtPrivate::QMetaTypeInterface **>(buf + size);
if constexpr (mode == Construct) {
meta->d.metaTypes = types;
for (const auto &prop : d->properties) {
QMetaType mt = prop.metaType;
*types = reinterpret_cast<QtPrivate::QMetaTypeInterface *&>(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<QtPrivate::QMetaTypeInterface *&>(mt);
types++;
for (const auto &parameterType: method.parameterTypes()) {
QMetaType mt = QMetaType::fromName(parameterType);
*types = reinterpret_cast<QtPrivate::QMetaTypeInterface *&>(mt);
types++;
}
}
for (const auto &constructor : d->constructors) {
for (const auto &parameterType : constructor.parameterTypes()) {
QMetaType mt = QMetaType::fromName(parameterType);
*types = reinterpret_cast<QtPrivate::QMetaTypeInterface *&>(mt);
types++;
for (const auto &parameterType: method.parameterTypes()) {
QMetaType mt = QMetaType::fromName(parameterType);
*types = reinterpret_cast<QtPrivate::QMetaTypeInterface *&>(mt);
types++;
}
}
for (const auto &constructor : d->constructors) {
for (const auto &parameterType : constructor.parameterTypes()) {
QMetaType mt = QMetaType::fromName(parameterType);
*types = reinterpret_cast<QtPrivate::QMetaTypeInterface *&>(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 *);

View File

@ -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)