From b5229df6a08a902b11a2fc9529af6385f4d985d5 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Mon, 7 Aug 2017 23:24:57 +0200 Subject: Do not crash on non-QVariant return types Patch e354bdc5 introduced a regression that triggers a crash in Qt 5.9 when returning a type that is not implicitly convertible to QVariant, such as a QJsonValue, from an invoked method/slot. This patch fixes this situation and adds proper unit test coverage. Change-Id: Ib8cb0c96e7496bc8dc9a628245d7a44e4234aff0 Task-number: QTBUG-62045 Reviewed-by: Frederik Gladhorn Reviewed-by: Kai Dohmen --- src/webchannel/qmetaobjectpublisher.cpp | 4 ++-- tests/auto/webchannel/tst_webchannel.cpp | 34 +++++++++++++++++++++++++++++--- tests/auto/webchannel/tst_webchannel.h | 15 +++++++------- 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp index dcc589c..cfc6ad2 100644 --- a/src/webchannel/qmetaobjectpublisher.cpp +++ b/src/webchannel/qmetaobjectpublisher.cpp @@ -383,12 +383,12 @@ QVariant QMetaObjectPublisher::invokeMethod(QObject *const object, const int met arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9]); } else { - QGenericReturnArgument returnArgument(method.typeName(), returnValue.data()); - // Only init variant with return type if its not a variant itself, which would // lead to nested variants which is not what we want. if (method.returnType() != QMetaType::QVariant) returnValue = QVariant(method.returnType(), 0); + + QGenericReturnArgument returnArgument(method.typeName(), returnValue.data()); method.invoke(object, returnArgument, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9]); diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp index 2e80477..f214b7e 100644 --- a/tests/auto/webchannel/tst_webchannel.cpp +++ b/tests/auto/webchannel/tst_webchannel.cpp @@ -536,6 +536,10 @@ void TestWebChannel::testInvokeMethodConversion() QVERIFY(method != -1); channel.d_func()->publisher->invokeMethod(this, method, args); QCOMPARE(m_lastInt, args.at(0).toInt()); + int getterMethod = metaObject()->indexOfMethod("readInt()"); + QVERIFY(getterMethod != -1); + auto retVal = channel.d_func()->publisher->invokeMethod(this, getterMethod, {}); + QCOMPARE(retVal, args.at(0).toVariant()); } { int method = metaObject()->indexOfMethod("setBool(bool)"); @@ -544,24 +548,40 @@ void TestWebChannel::testInvokeMethodConversion() args.append(QJsonValue(!m_lastBool)); channel.d_func()->publisher->invokeMethod(this, method, args); QCOMPARE(m_lastBool, args.at(0).toBool()); + int getterMethod = metaObject()->indexOfMethod("readBool()"); + QVERIFY(getterMethod != -1); + auto retVal = channel.d_func()->publisher->invokeMethod(this, getterMethod, {}); + QCOMPARE(retVal, args.at(0).toVariant()); } { int method = metaObject()->indexOfMethod("setDouble(double)"); QVERIFY(method != -1); channel.d_func()->publisher->invokeMethod(this, method, args); QCOMPARE(m_lastDouble, args.at(0).toDouble()); + int getterMethod = metaObject()->indexOfMethod("readDouble()"); + QVERIFY(getterMethod != -1); + auto retVal = channel.d_func()->publisher->invokeMethod(this, getterMethod, {}); + QCOMPARE(retVal, args.at(0).toVariant()); } { int method = metaObject()->indexOfMethod("setVariant(QVariant)"); QVERIFY(method != -1); channel.d_func()->publisher->invokeMethod(this, method, args); QCOMPARE(m_lastVariant, args.at(0).toVariant()); + int getterMethod = metaObject()->indexOfMethod("readVariant()"); + QVERIFY(getterMethod != -1); + auto retVal = channel.d_func()->publisher->invokeMethod(this, getterMethod, {}); + QCOMPARE(retVal, args.at(0).toVariant()); } { int method = metaObject()->indexOfMethod("setJsonValue(QJsonValue)"); QVERIFY(method != -1); channel.d_func()->publisher->invokeMethod(this, method, args); QCOMPARE(m_lastJsonValue, args.at(0)); + int getterMethod = metaObject()->indexOfMethod("readJsonValue()"); + QVERIFY(getterMethod != -1); + auto retVal = channel.d_func()->publisher->invokeMethod(this, getterMethod, {}); + QCOMPARE(retVal, args.at(0).toVariant()); } { int method = metaObject()->indexOfMethod("setJsonObject(QJsonObject)"); @@ -572,16 +592,24 @@ void TestWebChannel::testInvokeMethodConversion() args[0] = object; channel.d_func()->publisher->invokeMethod(this, method, args); QCOMPARE(m_lastJsonObject, object); + int getterMethod = metaObject()->indexOfMethod("readJsonObject()"); + QVERIFY(getterMethod != -1); + auto retVal = channel.d_func()->publisher->invokeMethod(this, getterMethod, {}); + QCOMPARE(retVal, QVariant::fromValue(object)); } { - int method = metaObject()->indexOfMethod("setJsonArray(QJsonArray)"); - QVERIFY(method != -1); + int setterMethod = metaObject()->indexOfMethod("setJsonArray(QJsonArray)"); + QVERIFY(setterMethod != -1); QJsonArray array; array << QJsonValue(123); array << QJsonValue(4.2); args[0] = array; - channel.d_func()->publisher->invokeMethod(this, method, args); + channel.d_func()->publisher->invokeMethod(this, setterMethod, args); QCOMPARE(m_lastJsonArray, array); + int getterMethod = metaObject()->indexOfMethod("readJsonArray()"); + QVERIFY(getterMethod != -1); + auto retVal = channel.d_func()->publisher->invokeMethod(this, getterMethod, {}); + QCOMPARE(retVal, QVariant::fromValue(array)); } } diff --git a/tests/auto/webchannel/tst_webchannel.h b/tests/auto/webchannel/tst_webchannel.h index aaacb5a..d2597e5 100644 --- a/tests/auto/webchannel/tst_webchannel.h +++ b/tests/auto/webchannel/tst_webchannel.h @@ -258,20 +258,21 @@ public: explicit TestWebChannel(QObject *parent = 0); virtual ~TestWebChannel(); +public slots: int readInt() const; - Q_INVOKABLE void setInt(int i); + void setInt(int i); bool readBool() const; - Q_INVOKABLE void setBool(bool b); + void setBool(bool b); double readDouble() const; - Q_INVOKABLE void setDouble(double d); + void setDouble(double d); QVariant readVariant() const; - Q_INVOKABLE void setVariant(const QVariant &v); + void setVariant(const QVariant &v); QJsonValue readJsonValue() const; - Q_INVOKABLE void setJsonValue(const QJsonValue &v); + void setJsonValue(const QJsonValue &v); QJsonObject readJsonObject() const; - Q_INVOKABLE void setJsonObject(const QJsonObject &v); + void setJsonObject(const QJsonObject &v); QJsonArray readJsonArray() const; - Q_INVOKABLE void setJsonArray(const QJsonArray &v); + void setJsonArray(const QJsonArray &v); signals: void lastIntChanged(); -- cgit v1.2.1