QVariant: Avoid crash when constructed from unsuitable metatype

If the metatype does not support copy and default construction, then it
it unsuitunsuitable for use in QMetaType. We cannot prevent users from
passing in such metatypes (as we have e.g. a ctor taking QMetaType), so
verify this in customConstruct, and make the variant invalid in that
case.

Change-Id: Ib1f0149c8fb9a1cce0049fd0311980754cc85d1b
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
(cherry picked from commit 6a0e59ed506ecb7d6a1bc17beedd938d36a1d26f)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Fabian Kosmale 2022-07-18 09:17:35 +02:00 committed by Qt Cherry-pick Bot
parent d726a463e7
commit 8826fb80f0
2 changed files with 57 additions and 3 deletions

View File

@ -220,11 +220,15 @@ static void customConstruct(QVariant::Private *d, const void *copy)
*d = QVariant::Private();
return;
}
if (!(iface->copyCtr && iface->defaultCtr)) {
// QVariant requires type to be copy and default constructible
*d = QVariant::Private();
qWarning("QVariant: Provided metatype does not support "
"destruction, copy and default construction");
return;
}
if (QVariant::Private::canUseInternalSpace(iface)) {
// QVariant requires type to be copy and default constructible
Q_ASSERT(iface->copyCtr);
Q_ASSERT(iface->defaultCtr);
if (copy)
iface->copyCtr(iface, &d->data, copy);
else
@ -781,6 +785,9 @@ QVariant::QVariant(const QVariant &p)
instead to construct variants from the pointer types represented by
\c QMetaType::VoidStar, and \c QMetaType::QObjectStar.
If \a type does not support copy and default construction, the variant will
be invalid.
\sa QVariant::fromValue(), QMetaType::Type
*/
QVariant::QVariant(QMetaType type, const void *copy) : d(type)

View File

@ -287,6 +287,9 @@ private slots:
void moveOperations();
void equalsWithoutMetaObject();
void constructFromIncompatibleMetaType_data();
void constructFromIncompatibleMetaType();
private:
void dataStream_data(QDataStream::Version version);
void loadQVariantFromDataStream(QDataStream::Version version);
@ -5107,5 +5110,49 @@ void tst_QVariant::equalsWithoutMetaObject()
QVERIFY(qobjectVariant != noMetaObjectVariant);
}
class NonDefaultConstructible
{
NonDefaultConstructible(int ) {}
};
struct Indestructible
{
Indestructible() {}
Indestructible(const Indestructible &) {}
Indestructible &operator=(const Indestructible &) { return *this; }
private:
~Indestructible() {}
};
void tst_QVariant::constructFromIncompatibleMetaType_data()
{
QTest::addColumn<QMetaType>("type");
auto addRow = [](QMetaType meta) {
QTest::newRow(meta.name()) << meta;
};
addRow(QMetaType::fromType<void>());
addRow(QMetaType::fromType<NonDefaultConstructible>());
addRow(QMetaType::fromType<QObject>());
addRow(QMetaType::fromType<Indestructible>());
}
void tst_QVariant::constructFromIncompatibleMetaType()
{
QFETCH(QMetaType, type);
// in that case, we run into a different condition (size == 0), and do not warn
if (QTest::currentDataTag() != QLatin1String("void"))
QTest::ignoreMessage(
QtWarningMsg,
"QVariant: Provided metatype does not support destruction, copy and default construction");
QVariant var(type, nullptr);
QVERIFY(!var.isValid());
QVERIFY(!var.metaType().isValid());
QVariant regular(1.0);
QVERIFY(!var.canView(type));
QVERIFY(!var.canConvert(type));
QVERIFY(!QVariant(regular).convert(type));
}
QTEST_MAIN(tst_QVariant)
#include "tst_qvariant.moc"