tst_qmetatype: fix memleaks

We didn't delete the new'ed up QMetaTypeInterfaces, causing asan to
complain.

Fix by storing them in strong references alongside their users in a
statically-allocated container.

We use shared_ptr to hold them, because QMetaTypeInterface doesn't
have a virtual destructor, so deleting objects of the TypeInfo types
(plural!) derived from QMetaTypeInterface though a pointer to the base
class is UB. The shared_ptr constructor, however, is templated, so it
stores the correct call (~TypeInfo()) in its type-erased deleter.

We can't use std::make_shared(), because that doesn't support
aggregate initialization until C++20, so we manually new up the
TypeInfos.

5.15 is not affected.

Pick-to: 6.3 6.2
Change-Id: Ic7ec88c34e02a9e0dd3421848c0c0885f4756702
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
This commit is contained in:
Marc Mutz 2021-12-22 09:16:36 +01:00
parent b6239f70f5
commit 58058794b1

View File

@ -36,6 +36,7 @@
#include <algorithm>
#include <memory>
#include <vector>
Q_DECLARE_METATYPE(QMetaType::Type)
@ -237,6 +238,12 @@ struct GenericPODType : BaseGenericType
QByteArray podData;
};
// The order of the next two statics matters!
//
// need to use shared_ptr, for its template ctor, since QMetaTypeInterface isn't polymorphic,
// but the test derives from it
static std::vector<std::shared_ptr<QtPrivate::QMetaTypeInterface>> s_metaTypeInterfaces;
using RegisteredType = QPair<std::shared_ptr<BaseGenericType>, std::shared_ptr<QMetaObject>>;
static QHash<int, RegisteredType> s_managedTypes;
@ -326,7 +333,7 @@ void tst_QMetaType::registerGadget(const char *name, const QList<GadgetPropertyT
QMetaObject *mo;
};
auto typeInfo = new TypeInfo {
auto typeInfo = s_metaTypeInterfaces.emplace_back(new TypeInfo {
{
0, alignof(GenericGadgetType), sizeof(GenericGadgetType), uint(flags), 0,
[](const QtPrivate::QMetaTypeInterface *self) -> const QMetaObject * {
@ -345,7 +352,7 @@ void tst_QMetaType::registerGadget(const char *name, const QList<GadgetPropertyT
nullptr
},
meta
};
}).get();
QMetaType gadgetMetaType(typeInfo);
dynamicGadgetProperties->m_metatype = gadgetMetaType;
int gadgetTypeId = QMetaType(typeInfo).id();
@ -1241,7 +1248,7 @@ void tst_QMetaType::typedConstruct()
dynamicGadgetProperties->podData = myPodTesData;
const auto flags = QMetaType::NeedsConstruction | QMetaType::NeedsDestruction;
using TypeInfo = QtPrivate::QMetaTypeInterface;
auto typeInfo = new TypeInfo {
auto typeInfo = s_metaTypeInterfaces.emplace_back(new TypeInfo {
0, alignof(GenericGadgetType), sizeof(GenericGadgetType), uint(flags), 0, nullptr, podTypeName,
[](const TypeInfo *self, void *where) { GadgetTypedConstructor(self->typeId, where, nullptr); },
[](const TypeInfo *self, void *where, const void *copy) { GadgetTypedConstructor(self->typeId, where, copy); },
@ -1253,7 +1260,7 @@ void tst_QMetaType::typedConstruct()
GadgetSaveOperator,
GadgetLoadOperator,
nullptr
};
}).get();
QMetaType metatype(typeInfo);
dynamicGadgetProperties->m_metatype = metatype;
int podTypeId = metatype.id();