Fix crash in QMetaProperty::write for custom types and conversion

if t >= QMetaType::User, we would not return false nor call convert.
We would then pass a pointer to whatever is in the QVariant to the
qt_metacall that is expecting a pointer to an object of a different type.

Since we have custom converters, we can call QVarent::convert even for
custom types anyway.

[ChangeLog][QtCore] Fixed crash when setting a QVariant of a different
type to a property of a custom type. Attempt to do a conversion instead.

Task-number: QTBUG-40644
Change-Id: Ib6fbd7e7ddcf25c5ee247ea04177e079f6d7de35
Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@theqtcompany.com>
This commit is contained in:
Olivier Goffart 2015-09-30 23:27:20 +02:00 committed by Olivier Goffart (Woboq GmbH)
parent 3ae1eb6236
commit a3a7d485fa
3 changed files with 49 additions and 3 deletions

View File

@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2014 Olivier Goffart <ogoffart@woboq.com>
** Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com>
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -3068,7 +3068,7 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const
if (t == QMetaType::UnknownType)
return false;
}
if (t != QMetaType::QVariant && t != (uint)value.userType() && (t < QMetaType::User && !v.convert((QVariant::Type)t)))
if (t != QMetaType::QVariant && int(t) != value.userType() && !v.convert(t))
return false;
}

View File

@ -366,6 +366,9 @@ static int writeProperty(QObject *obj, const QByteArray &property_name, QVariant
value = other;
}
if (mp.userType() == qMetaTypeId<QDBusVariant>())
value = QVariant::fromValue(QDBusVariant(value));
// the property type here should match
return mp.write(obj, value) ? PropertyWriteSuccess : PropertyWriteFailed;
}

View File

@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2014 Olivier Goffart <ogoffart@woboq.com>
** Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com>
** Contact: http://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
@ -38,15 +38,29 @@
#include <qobject.h>
#include <qmetaobject.h>
struct CustomType
{
int padding;
QString str;
CustomType(const QString &str = QString()) : str(str) {}
operator QString() const { return str; }
friend bool operator!=(const CustomType &a, const CustomType &b)
{ return a.str != b.str; }
};
Q_DECLARE_METATYPE(CustomType)
class tst_QMetaProperty : public QObject
{
Q_OBJECT
Q_PROPERTY(EnumType value WRITE setValue READ getValue)
Q_PROPERTY(EnumType value2 WRITE set_value READ get_value)
Q_PROPERTY(QString value7 MEMBER value7)
Q_PROPERTY(int value8 READ value8)
Q_PROPERTY(int value9 READ value9 CONSTANT)
Q_PROPERTY(int value10 READ value10 FINAL)
Q_PROPERTY(QMap<int, int> map MEMBER map)
Q_PROPERTY(CustomType custom MEMBER custom)
private slots:
void hasStdCppSet();
@ -55,6 +69,7 @@ private slots:
void gadget();
void readAndWriteWithLazyRegistration();
void mapProperty();
void conversion();
public:
enum EnumType { EnumType1 };
@ -68,7 +83,9 @@ public:
int value9() const { return 1; }
int value10() const { return 1; }
QString value7;
QMap<int, int> map;
CustomType custom;
};
void tst_QMetaProperty::hasStdCppSet()
@ -195,5 +212,31 @@ void tst_QMetaProperty::mapProperty()
QCOMPARE(map, (v.value<QMap<int,int> >()));
}
void tst_QMetaProperty::conversion()
{
QMetaType::registerConverter<QString, CustomType>();
QMetaType::registerConverter<CustomType, QString>();
QString hello = QStringLiteral("Hello");
// Write to a QString property using a CustomType in a QVariant
QMetaProperty value7P = metaObject()->property(metaObject()->indexOfProperty("value7"));
QVERIFY(value7P.isValid());
QVERIFY(value7P.write(this, QVariant::fromValue(CustomType(hello))));
QCOMPARE(value7, hello);
// Write to a CustomType property using a QString in a QVariant
QMetaProperty customP = metaObject()->property(metaObject()->indexOfProperty("custom"));
QVERIFY(customP.isValid());
QVERIFY(customP.write(this, hello));
QCOMPARE(custom.str, hello);
// Something that cannot be converted should fail
QVERIFY(!customP.write(this, 45));
QVERIFY(!customP.write(this, QVariant::fromValue(this)));
QVERIFY(!value7P.write(this, QVariant::fromValue(this)));
QVERIFY(!value7P.write(this, QVariant::fromValue<QObject*>(this)));
}
QTEST_MAIN(tst_QMetaProperty)
#include "tst_qmetaproperty.moc"