aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Webster <awebster@arcx.com>2019-07-22 15:29:38 -0400
committerAndrew Webster <awebster@arcx.com>2019-09-20 08:32:44 -0400
commit26fbc4038223f5571dd048c1d800458708b6972c (patch)
tree95eeb6a23d5d7cbddb7aacebcee25aa3c27beec0
parent869a1a5f7321dcd3fdd57735fb503a6d3506c616 (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.cpp1
-rw-r--r--src/webchannel/variantargument_p.h4
-rw-r--r--tests/auto/qml/testobject.cpp5
-rw-r--r--tests/auto/qml/testobject.h1
-rw-r--r--tests/auto/qml/tst_webchannel.qml34
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]);
+ }
}