diff options
author | Andrew Webster <awebster@arcx.com> | 2019-07-22 15:29:38 -0400 |
---|---|---|
committer | Andrew Webster <awebster@arcx.com> | 2019-09-20 08:32:44 -0400 |
commit | 26fbc4038223f5571dd048c1d800458708b6972c (patch) | |
tree | 95eeb6a23d5d7cbddb7aacebcee25aa3c27beec0 | |
parent | 869a1a5f7321dcd3fdd57735fb503a6d3506c616 (diff) |
Pack QVariants into args when QVariant is expected
When a method expects an argument of type QVariant, the argument should
actually contain a QVariant as opposed to the converted QVariant value.
If the converted value is given, which was the logic before this patch,
then some values may not be properly converted back to a QVariant when
the method is actually invoked (null for example).
For example, if a method signature is as follows:
Q_INVOKABLE void test(QVariant value);
And it is called from ECMAScript via WebChannel as follows:
obj.test(null)
Then the argument would have been created as type 'std::nullptr_t'
and passed into the method. This results in a QVariant with a
random type, which could cause a warning or even a segmentation fault
depending on what the type ends up as.
Instead, this patch creates the argument as a 'QVariant' which
results in the proper type when the method is invoked.
Change-Id: I3f75048da1c0f32707f6f162844de74157f0b535
Reviewed-by: Milian Wolff <milian.wolff@kdab.com>
-rw-r--r-- | src/webchannel/qmetaobjectpublisher.cpp | 1 | ||||
-rw-r--r-- | src/webchannel/variantargument_p.h | 4 | ||||
-rw-r--r-- | tests/auto/qml/testobject.cpp | 5 | ||||
-rw-r--r-- | tests/auto/qml/testobject.h | 1 | ||||
-rw-r--r-- | tests/auto/qml/tst_webchannel.qml | 34 |
5 files changed, 45 insertions, 0 deletions
diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp index e23921d..3907dfe 100644 --- a/src/webchannel/qmetaobjectpublisher.cpp +++ b/src/webchannel/qmetaobjectpublisher.cpp @@ -457,6 +457,7 @@ QVariant QMetaObjectPublisher::invokeMethod(QObject *const object, const QMetaMe VariantArgument arguments[10]; for (int i = 0; i < qMin(args.size(), method.parameterCount()); ++i) { arguments[i].value = toVariant(args.at(i), method.parameterType(i)); + arguments[i].type = method.parameterType(i); } // construct QGenericReturnArgument QVariant returnValue; diff --git a/src/webchannel/variantargument_p.h b/src/webchannel/variantargument_p.h index 263a742..afac507 100644 --- a/src/webchannel/variantargument_p.h +++ b/src/webchannel/variantargument_p.h @@ -62,6 +62,9 @@ struct VariantArgument { operator QGenericArgument() const { + if (type == QMetaType::QVariant) { + return Q_ARG(QVariant, value); + } if (!value.isValid()) { return QGenericArgument(); } @@ -69,6 +72,7 @@ struct VariantArgument } QVariant value; + int type; }; QT_END_NAMESPACE diff --git a/tests/auto/qml/testobject.cpp b/tests/auto/qml/testobject.cpp index ad302e7..8f565ee 100644 --- a/tests/auto/qml/testobject.cpp +++ b/tests/auto/qml/testobject.cpp @@ -77,4 +77,9 @@ QString TestObject::testOverload(const QString &str, int i) return str.toUpper() + QString::number(i + 1); } +int TestObject::testVariantType(const QVariant &val) +{ + return val.type(); +} + QT_END_NAMESPACE diff --git a/tests/auto/qml/testobject.h b/tests/auto/qml/testobject.h index b9c5ecc..a8d8f7f 100644 --- a/tests/auto/qml/testobject.h +++ b/tests/auto/qml/testobject.h @@ -51,6 +51,7 @@ public slots: int testOverload(int i); QString testOverload(const QString &str); QString testOverload(const QString &str, int i); + int testVariantType(const QVariant &val); signals: void testSignalBool(bool testBool); diff --git a/tests/auto/qml/tst_webchannel.qml b/tests/auto/qml/tst_webchannel.qml index ed1c4a1..fe9aa35 100644 --- a/tests/auto/qml/tst_webchannel.qml +++ b/tests/auto/qml/tst_webchannel.qml @@ -556,4 +556,38 @@ TestCase { compare(signalArgs_explicit3, [["the answer is ", 41]]); compare(returnValues, [100, 42, "HELLO WORLD", "THE ANSWER IS 42"]); } + + function test_variantType() + { + var returnValues = []; + function logReturnValue(value) { + returnValues.push(value); + } + var channel = client.createChannel(function(channel) { + var testObject = channel.objects.testObject; + testObject.testVariantType(0, logReturnValue); + testObject.testVariantType("0", logReturnValue); + testObject.testVariantType(null, logReturnValue); + }); + client.awaitInit(); + + function awaitMessage(type) + { + var msg = client.awaitMessage(); + compare(msg.type, type); + compare(msg.object, "testObject"); + } + + console.log("double arg"); + awaitMessage(JSClient.QWebChannelMessageTypes.invokeMethod); + console.log("string arg"); + awaitMessage(JSClient.QWebChannelMessageTypes.invokeMethod); + console.log("null arg"); + awaitMessage(JSClient.QWebChannelMessageTypes.invokeMethod); + + client.awaitIdle(); + + // QMetaType::Double: 6, QMetaType::QString: 10, QMetaType::Nullptr: 51 + compare(returnValues, [6, 10, 51]); + } } |