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:
parent
d726a463e7
commit
8826fb80f0
@ -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)
|
||||
|
@ -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…
x
Reference in New Issue
Block a user