summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJannis Voelker <jannis.voelker@basyskom.com>2018-04-27 10:30:57 +0200
committerJannis Völker <jannis.voelker@basyskom.com>2018-05-04 10:19:53 +0000
commite4ab7f3be061f3ed2102df6031630fc82aeef9b5 (patch)
treeac30279e22938e66348f4ea79c78609eda6eb8f9
parentdeb7c35ee73e3599a17c9933262917d73a775711 (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.cpp18
-rw-r--r--tests/auto/qopcuaclient/tst_client.cpp15
-rw-r--r--tests/open62541-testserver/main.cpp2
-rw-r--r--tests/open62541-testserver/testserver.cpp36
-rw-r--r--tests/open62541-testserver/testserver.h1
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);