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. Pick-to: 6.2 6.3 6.4 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>bb10
parent
030923c0de
commit
6a0e59ed50
|
|
@ -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
|
||||
|
|
@ -778,6 +782,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)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in New Issue