diff options
author | Jannis Voelker <jannis.voelker@basyskom.com> | 2018-04-27 10:30:57 +0200 |
---|---|---|
committer | Jannis Völker <jannis.voelker@basyskom.com> | 2018-05-04 10:19:53 +0000 |
commit | e4ab7f3be061f3ed2102df6031630fc82aeef9b5 (patch) | |
tree | ac30279e22938e66348f4ea79c78609eda6eb8f9 | |
parent | deb7c35ee73e3599a17c9933262917d73a775711 (diff) |
Fix crash when converting empty array variants (open62541)
If arrayLength is 0, the variant can contain a scalar value or
an empty array. Empty arrays are indicated by setting data to 1.
This must be checked before calling scalarToQVariant().
Change-Id: Ia62c4acf258fb0e080334504d105de1a898e3e6a
Reviewed-by: Frank Meerkoetter <frank.meerkoetter@basyskom.com>
-rw-r--r-- | src/plugins/opcua/open62541/qopen62541valueconverter.cpp | 18 | ||||
-rw-r--r-- | tests/auto/qopcuaclient/tst_client.cpp | 15 | ||||
-rw-r--r-- | tests/open62541-testserver/main.cpp | 2 | ||||
-rw-r--r-- | tests/open62541-testserver/testserver.cpp | 36 | ||||
-rw-r--r-- | tests/open62541-testserver/testserver.h | 1 |
5 files changed, 67 insertions, 5 deletions
diff --git a/src/plugins/opcua/open62541/qopen62541valueconverter.cpp b/src/plugins/opcua/open62541/qopen62541valueconverter.cpp index 7024523..226b8b7 100644 --- a/src/plugins/opcua/open62541/qopen62541valueconverter.cpp +++ b/src/plugins/opcua/open62541/qopen62541valueconverter.cpp @@ -412,16 +412,24 @@ QVariant scalarToQVariant<QVariant, UA_ExtensionObject>(UA_ExtensionObject *data template<typename TARGETTYPE, typename UATYPE> QVariant arrayToQVariant(const UA_Variant &var, QMetaType::Type type) { - if (var.arrayLength > 1) { + UATYPE *temp = static_cast<UATYPE *>(var.data); + + if (var.arrayLength > 0) { QVariantList list; for (size_t i = 0; i < var.arrayLength; ++i) { - UATYPE *temp = static_cast<UATYPE *>(var.data); list.append(scalarToQVariant<TARGETTYPE, UATYPE>(&temp[i], type)); } - return list; + if (list.size() == 1) + return list.at(0); + else + return list; + } else if (UA_Variant_isScalar(&var)) { + return scalarToQVariant<TARGETTYPE, UATYPE>(temp, type); + } else if (var.arrayLength == 0 && var.data == UA_EMPTY_ARRAY_SENTINEL) { + return QVariantList(); // Return empty QVariantList for empty array } - UATYPE *temp = static_cast<UATYPE *>(var.data); - return scalarToQVariant<TARGETTYPE, UATYPE>(temp, type); + + return QVariant(); // Return empty QVariant for empty scalar variant } template<typename TARGETTYPE, typename QTTYPE> diff --git a/tests/auto/qopcuaclient/tst_client.cpp b/tests/auto/qopcuaclient/tst_client.cpp index 069ea75..b9b0d99 100644 --- a/tests/auto/qopcuaclient/tst_client.cpp +++ b/tests/auto/qopcuaclient/tst_client.cpp @@ -188,6 +188,8 @@ private slots: void writeInvalidNode(); defineDataMethod(writeMultipleAttributes_data) void writeMultipleAttributes(); + defineDataMethod(readEmptyArrayVariable_data) + void readEmptyArrayVariable(); defineDataMethod(getRootNode_data) void getRootNode(); @@ -506,6 +508,19 @@ void Tst_QOpcUaClient::writeMultipleAttributes() QVERIFY(node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUa::QQualifiedName>() == QOpcUa::QQualifiedName(2, QStringLiteral("TestString"))); } +void Tst_QOpcUaClient::readEmptyArrayVariable() +{ + QFETCH(QOpcUaClient *, opcuaClient); + OpcuaConnector connector(opcuaClient, m_endpoint); + + QScopedPointer<QOpcUaNode> node(opcuaClient->node("ns=2;s=EmptyBoolArray")); + QVERIFY(node != 0); + + READ_MANDATORY_VARIABLE_NODE(node); + QCOMPARE(node->attribute(QOpcUa::NodeAttribute::Value).type(), QVariant::List); + QVERIFY(node->attribute(QOpcUa::NodeAttribute::Value).toList().isEmpty()); +} + void Tst_QOpcUaClient::getRootNode() { QFETCH(QOpcUaClient *, opcuaClient); diff --git a/tests/open62541-testserver/main.cpp b/tests/open62541-testserver/main.cpp index 55907fa..8f41763 100644 --- a/tests/open62541-testserver/main.cpp +++ b/tests/open62541-testserver/main.cpp @@ -156,5 +156,7 @@ int main(int argc, char **argv) server.addMethod(testFolder, "ns=3;s=Test.Method.Multiply", "MultiplyDoubles"); + server.addEmptyArrayVariable(testFolder, "ns=2;s=EmptyBoolArray", "EmptyBoolArrayTest"); + return app.exec(); } diff --git a/tests/open62541-testserver/testserver.cpp b/tests/open62541-testserver/testserver.cpp index 22d3fd2..d02d5c8 100644 --- a/tests/open62541-testserver/testserver.cpp +++ b/tests/open62541-testserver/testserver.cpp @@ -192,6 +192,42 @@ UA_NodeId TestServer::addVariable(const UA_NodeId &folder, const QString &variab return resultId; } +UA_NodeId TestServer::addEmptyArrayVariable(const UA_NodeId &folder, const QString &variableNode, const QString &name) +{ + UA_NodeId variableNodeId = Open62541Utils::nodeIdFromQString(variableNode); + + UA_VariableAttributes attr = UA_VariableAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", name.toUtf8().constData()); + attr.dataType = UA_TYPES[UA_TYPES_BOOLEAN].typeId; + attr.accessLevel = UA_ACCESSLEVELMASK_READ; + attr.valueRank = 1; + attr.value.arrayLength = 0; + attr.value.type = &UA_TYPES[UA_TYPES_BOOLEAN]; + attr.value.data = UA_EMPTY_ARRAY_SENTINEL; + + UA_QualifiedName variableName; + variableName.namespaceIndex = variableNodeId.namespaceIndex; + variableName.name = attr.displayName.text; + + UA_NodeId resultId; + UA_StatusCode result = UA_Server_addVariableNode(m_server, + variableNodeId, + folder, + UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), + variableName, + UA_NODEID_NULL, + attr, + NULL, + &resultId); + + if (result != UA_STATUSCODE_GOOD) { + qWarning() << "Could not add empty array variable:" << result; + return UA_NODEID_NULL; + } + + return resultId; +} + UA_StatusCode TestServer::multiplyMethod(UA_Server *server, const UA_NodeId *sessionId, void *sessionHandle, const UA_NodeId *methodId, void *methodContext, const UA_NodeId *objectId, void *objectContext, size_t inputSize, const UA_Variant *input, size_t outputSize, UA_Variant *output) { Q_UNUSED(server); diff --git a/tests/open62541-testserver/testserver.h b/tests/open62541-testserver/testserver.h index 046a994..9f69ab6 100644 --- a/tests/open62541-testserver/testserver.h +++ b/tests/open62541-testserver/testserver.h @@ -60,6 +60,7 @@ public: UA_NodeId addObject(const UA_NodeId &folderId, int namespaceIndex, const QString &objectName = QString()); UA_NodeId addVariable(const UA_NodeId &folder, const QString &variableNode, const QString &name, const QVariant &value, QOpcUa::Types type); + UA_NodeId addEmptyArrayVariable(const UA_NodeId &folder, const QString &variableNode, const QString &name); UA_NodeId addMethod(const UA_NodeId &folder, const QString &variableNode, const QString &description); |