Browse Source

variant array dimensions as uint32; use same value/variable consistency check of method arguments

Julius Pfrommer 7 years ago
parent
commit
bf8b10f775

+ 1 - 1
include/ua_types.h

@@ -575,7 +575,7 @@ typedef struct {
     size_t arrayLength;         /* The number of elements in the data array */
     void *data;                 /* Points to the scalar or array data */
     size_t arrayDimensionsSize; /* The number of dimensions the data-array has */
-    UA_Int32 *arrayDimensions;  /* The length of each dimension */
+    UA_UInt32 *arrayDimensions; /* The length of each dimension */
 } UA_Variant;
 
 /* Returns true if the variant contains a scalar value. Note that empty variants

+ 1 - 1
src/server/ua_nodes.h

@@ -28,7 +28,7 @@ typedef enum {
                         /* n = -2: the value can be a scalar or an array with any number of dimensions */ \
                         /* n = -3: the value can be a scalar or a one dimensional array */                \
     size_t arrayDimensionsSize;                                         \
-    UA_Int32 *arrayDimensions;                                          \
+    UA_UInt32 *arrayDimensions;                                         \
                                                                         \
     /* The current value */                                             \
     UA_ValueSource valueSource;                                         \

+ 5 - 2
src/server/ua_server_internal.h

@@ -103,8 +103,11 @@ isNodeInTree(UA_NodeStore *ns, const UA_NodeId *rootNode, const UA_NodeId *nodeT
              const UA_NodeId *referenceTypeIds, size_t referenceTypeIdsSize,
              size_t maxDepth, UA_Boolean *found);
 
-/* find a datatype from the nodeid */
-const UA_DataType * findDataType(const UA_NodeId *typeId);
+UA_StatusCode
+UA_Variant_matchVariableDefinition(UA_Server *server, const UA_NodeId *variableDataTypeId,
+                                   UA_Int32 variableValueRank, size_t variableArrayDimensionsSize,
+                                   const UA_UInt32 *variableArrayDimensions, const UA_Variant *value,
+                                   const UA_NumericRange *range, UA_Variant *equivalent);
 
 /* Set the value attribute inside a node */
 UA_StatusCode

+ 47 - 42
src/server/ua_services_attribute.c

@@ -567,7 +567,7 @@ writeDataTypeAttribute(UA_Server *server, UA_VariableNode *node,
     return UA_STATUSCODE_GOOD; 
 }
 
-const UA_DataType *
+static const UA_DataType *
 findDataType(const UA_NodeId *typeId) {
     for(size_t i = 0; i < UA_TYPES_COUNT; i++) {
         if (UA_TYPES[i].typeId.identifier.numeric == typeId->identifier.numeric)
@@ -586,54 +586,58 @@ static enum type_equivalence typeEquivalence(const UA_DataType *t) {
     return TYPE_EQUIVALENCE_NONE;
 }
 
-/* Tests whether the value can be written into a node. Sometimes it can be
- * necessary to transform the content of the value, e.g. byte array to
- * bytestring or uint32 to some enum. If successful the equivalent variant
- * contains the correct definition (NODELETE, pointing to the members of the
- * original value, so do not delete) */
-static UA_StatusCode
-matchValueWithNodeDefinition(UA_Server *server, const UA_VariableNode *node,
-                             const UA_Variant *value, const UA_NumericRange *range,
-                             UA_Variant *equivalent) {
+/* Tests whether the value matches a variable definition given by
+ * - datatype
+ * - valueranke
+ * - array dimensions.
+ * Sometimes it can be necessary to transform the content of the value, e.g.
+ * byte array to bytestring or uint32 to some enum. If successful the equivalent
+ * variant contains the possibly corrected definition (NODELETE, pointing to the
+ * members of the original value, so do not delete) */
+UA_StatusCode
+UA_Variant_matchVariableDefinition(UA_Server *server, const UA_NodeId *variableDataTypeId,
+                                   UA_Int32 variableValueRank, size_t variableArrayDimensionsSize,
+                                   const UA_UInt32 *variableArrayDimensions, const UA_Variant *value,
+                                   const UA_NumericRange *range, UA_Variant *equivalent) {
     /* Prepare the output variant */
-    *equivalent = *value;
-    equivalent->storageType = UA_VARIANT_DATA_NODELETE;
+    if(equivalent) {
+        *equivalent = *value;
+        equivalent->storageType = UA_VARIANT_DATA_NODELETE;
+    }
 
     /* No content is only allowed for BaseDataType */
-    const UA_NodeId *dataType;
+    const UA_NodeId *valueDataTypeId;
     UA_NodeId basedatatype = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE);
     if(value->type)
-        dataType = &value->type->typeId;
+        valueDataTypeId = &value->type->typeId;
     else
-        dataType = &basedatatype;
+        valueDataTypeId = &basedatatype;
     
     /* See if the types match. The nodeid on the wire may be != the nodeid in
      * the node for opaque types, enums and bytestrings. value contains the
      * correct type definition after the following paragraph */
-    if(!UA_NodeId_equal(&node->dataType, dataType)) {
+    if(!UA_NodeId_equal(valueDataTypeId, variableDataTypeId)) {
 
         /* is this a subtype? */
         UA_NodeId subtypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
         UA_Boolean found = false;
-        UA_StatusCode retval = isNodeInTree(server->nodestore, dataType,
-                                            &node->dataType, &subtypeId,
-                                            1, 10, &found);
+        UA_StatusCode retval = isNodeInTree(server->nodestore, valueDataTypeId,
+                                            variableDataTypeId, &subtypeId, 1, 10, &found);
         if(retval != UA_STATUSCODE_GOOD)
             return retval;
         if(found)
             goto check_array;
 
-        /* compare the datatypes for equivalence */
-        const UA_DataType *nodeDataType = findDataType(&node->dataType);
-        const UA_DataType *valueDataType = value->type;
-        if(!nodeDataType || !valueDataType)
+        const UA_DataType *variableDataType = findDataType(variableDataTypeId);
+        const UA_DataType *valueDataType = findDataType(valueDataTypeId);
+        if(!equivalent || !variableDataType || !valueDataType)
             return UA_STATUSCODE_BADTYPEMISMATCH;
 
-        /* a string is written to a byte array */
-        if(nodeDataType == &UA_TYPES[UA_TYPES_BYTE] &&
+        /* a string is written to a byte array. the valuerank and array
+           dimensions are checked later */
+        if(variableDataType == &UA_TYPES[UA_TYPES_BYTE] &&
            valueDataType == &UA_TYPES[UA_TYPES_BYTESTRING] &&
-           !UA_Variant_isScalar(&node->value.data.value.value) &&
-           UA_Variant_isScalar(value)) {
+           !range && !UA_Variant_isScalar(value)) {
             UA_ByteString *str = (UA_ByteString*)value->data;
             equivalent->type = &UA_TYPES[UA_TYPES_BYTE];
             equivalent->arrayLength = str->length;
@@ -643,10 +647,10 @@ matchValueWithNodeDefinition(UA_Server *server, const UA_VariableNode *node,
 
         /* An enum was sent as an int32, or an opaque type as a bytestring. This
          * is detected with the typeIndex indicating the "true" datatype. */
-        enum type_equivalence te1 = typeEquivalence(nodeDataType);
+        enum type_equivalence te1 = typeEquivalence(variableDataType);
         enum type_equivalence te2 = typeEquivalence(valueDataType);
         if(te1 != TYPE_EQUIVALENCE_NONE && te1 == te2) {
-            equivalent->type = nodeDataType;
+            equivalent->type = variableDataType;
             goto check_array;
         }
 
@@ -656,7 +660,7 @@ matchValueWithNodeDefinition(UA_Server *server, const UA_VariableNode *node,
 
  check_array:
     /* Check if the valuerank allows for the value dimension */
-    switch(node->valueRank) {
+    switch(variableValueRank) {
     case -3: /* the value can be a scalar or a one dimensional array */
         if(value->arrayDimensionsSize > 1)
             return UA_STATUSCODE_BADTYPEMISMATCH;
@@ -671,7 +675,7 @@ matchValueWithNodeDefinition(UA_Server *server, const UA_VariableNode *node,
             return UA_STATUSCODE_BADTYPEMISMATCH;
         break;
     default: /* >= 1: the value is an array with the specified number of dimensions */
-        if(value->arrayDimensionsSize != (size_t)node->valueRank)
+        if(value->arrayDimensionsSize != (size_t)variableValueRank)
             return UA_STATUSCODE_BADTYPEMISMATCH;
     }
 
@@ -680,13 +684,13 @@ matchValueWithNodeDefinition(UA_Server *server, const UA_VariableNode *node,
         return UA_STATUSCODE_GOOD;
 
     /* See if the array dimensions match */
-    if(node->arrayDimensions) {
-        if(value->arrayDimensionsSize != node->arrayDimensionsSize)
+    if(variableArrayDimensions) {
+        if(value->arrayDimensionsSize != variableArrayDimensionsSize)
             return UA_STATUSCODE_BADTYPEMISMATCH;
         /* dimension size zero in the node definition: this value dimension can be any size */
-        for(size_t i = 0; i < node->arrayDimensionsSize; i++) {
-            if(node->arrayDimensions[i] != value->arrayDimensions[i] &&
-               node->arrayDimensions[i] != 0)
+        for(size_t i = 0; i < variableArrayDimensionsSize; i++) {
+            if(variableArrayDimensions[i] != value->arrayDimensions[i] &&
+               variableArrayDimensions[i] != 0)
                 return UA_STATUSCODE_BADTYPEMISMATCH;
         }
     }
@@ -714,8 +718,9 @@ writeValueAttribute(UA_Server *server, UA_VariableNode *node,
     UA_DataValue equivValue;
     if(value->hasValue) {
         equivValue = *value;
-        retval = matchValueWithNodeDefinition(server, node, &value->value,
-                                              rangeptr, &equivValue.value);
+        retval = UA_Variant_matchVariableDefinition(server, &node->dataType, node->valueRank,
+                                                    node->arrayDimensionsSize, node->arrayDimensions,
+                                                    &value->value, rangeptr, &equivValue.value);
         if(retval != UA_STATUSCODE_GOOD)
             goto cleanup;
         value = &equivValue;
@@ -850,8 +855,8 @@ CopyAttributeIntoNode(UA_Server *server, UA_Session *session,
     case UA_ATTRIBUTEID_DATATYPE:
         CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_DATATYPE(NODEID);
-        /* TODO: Check if the current value remains valid */
-        retval = writeDataTypeAttribute(server, (UA_VariableNode*)node, (const UA_NodeId*)value);
+        /* TODO */
+        retval = UA_STATUSCODE_BADNOTWRITABLE;
         break;
     case UA_ATTRIBUTEID_VALUERANK:
         CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
@@ -976,11 +981,11 @@ __UA_Server_write(UA_Server *server, const UA_NodeId *nodeId,
     UA_WriteValue_init(&wvalue);
     wvalue.nodeId = *nodeId;
     wvalue.attributeId = attributeId;
-    if(attributeId != UA_ATTRIBUTEID_VALUE)
+    if(attributeId != UA_ATTRIBUTEID_VALUE) {
         /* hacked cast. the target WriteValue is used as const anyway */
         UA_Variant_setScalar(&wvalue.value.value, (void*)(uintptr_t)value,
                              attr_type);
-    else {
+    } else {
         if(attr_type != &UA_TYPES[UA_TYPES_VARIANT])
             return UA_STATUSCODE_BADTYPEMISMATCH;
         wvalue.value.value = *(const UA_Variant*)value;

+ 41 - 107
src/server/ua_services_call.c

@@ -25,83 +25,8 @@ getArgumentsVariableNode(UA_Server *server, const UA_MethodNode *ofMethod,
 }
 
 static UA_StatusCode
-satisfySignature(UA_Server *server, const UA_Variant *var, const UA_Argument *arg) {
-  if(var == NULL || var->type == NULL) 
-    return UA_STATUSCODE_BADINVALIDARGUMENT;
-  
-  if(!UA_NodeId_equal(&var->type->typeId, &arg->dataType)){
-        if(!UA_NodeId_equal(&var->type->typeId, &UA_TYPES[UA_TYPES_INT32].typeId))
-            return UA_STATUSCODE_BADINVALIDARGUMENT;
-
-        /* enumerations are encoded as int32 -> if provided var is integer, check if arg is an enumeration type */
-        UA_NodeId enumerationNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ENUMERATION);
-        UA_NodeId hasSubTypeNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_HASSUBTYPE);
-        UA_Boolean found = false;
-        UA_StatusCode retval = isNodeInTree(server->nodestore, &arg->dataType, &enumerationNodeId, &hasSubTypeNodeId, 1, 1, &found);
-        if(retval != UA_STATUSCODE_GOOD)
-            return UA_STATUSCODE_BADINTERNALERROR;
-        if(!found)
-            return UA_STATUSCODE_BADINVALIDARGUMENT;
-    }
-
-    // Note: The namespace compiler will compile nodes with their actual array dimensions
-    // Todo: Check if this is standard conform for scalars
-    if(arg->arrayDimensionsSize > 0 && var->arrayDimensionsSize > 0)
-        if(var->arrayDimensionsSize != arg->arrayDimensionsSize)
-            return UA_STATUSCODE_BADINVALIDARGUMENT;
-
-    UA_Int32 *varDims = var->arrayDimensions;
-    size_t varDimsSize = var->arrayDimensionsSize;
-    UA_Boolean scalar = UA_Variant_isScalar(var);
-
-    /* The dimension 1 is implicit in the array length */
-    UA_Int32 fakeDims;
-    if(!scalar && !varDims) {
-        fakeDims = (UA_Int32)var->arrayLength;
-        varDims = &fakeDims;
-        varDimsSize = 1;
-    }
-
-    /* ValueRank Semantics
-     *  n >= 1: the value is an array with the specified number of dimens*ions.
-     *  n = 0: the value is an array with one or more dimensions.
-     *  n = -1: the value is a scalar.
-     *  n = -2: the value can be a scalar or an array with any number of dimensions.
-     *  n = -3:  the value can be a scalar or a one dimensional array. */
-    switch(arg->valueRank) {
-    case -3:
-        if(varDimsSize > 1)
-            return UA_STATUSCODE_BADINVALIDARGUMENT;
-        break;
-    case -2:
-        break;
-    case -1:
-        if(!scalar)
-            return UA_STATUSCODE_BADINVALIDARGUMENT;
-        break;
-    case 0:
-        if(scalar || !varDims)
-            return UA_STATUSCODE_BADINVALIDARGUMENT;
-        break;
-    default:
-        break;
-    }
-
-    /* Do the variants dimensions match? Check only if defined in the argument. */
-    if(arg->arrayDimensionsSize > 0) {
-        if(arg->arrayDimensionsSize != varDimsSize)
-            return UA_STATUSCODE_BADINVALIDARGUMENT;
-        for(size_t i = 0; i < varDimsSize; i++) {
-            // A value of 0 for an individual dimension indicates that the dimension has a variable	length.
-            if((UA_Int32)arg->arrayDimensions[i]!=0 && (UA_Int32)arg->arrayDimensions[i] != varDims[i])
-                return UA_STATUSCODE_BADINVALIDARGUMENT;
-        }
-    }
-    return UA_STATUSCODE_GOOD;
-}
-
-static UA_StatusCode
-argConformsToDefinition(UA_Server *server, const UA_VariableNode *argRequirements, size_t argsSize, const UA_Variant *args) {
+argumentsConformsToDefinition(UA_Server *server, const UA_VariableNode *argRequirements,
+                              size_t argsSize, const UA_Variant *args) {
     if(argRequirements->value.data.value.value.type != &UA_TYPES[UA_TYPES_ARGUMENT])
         return UA_STATUSCODE_BADINTERNALERROR;
     UA_Argument *argReqs = (UA_Argument*)argRequirements->value.data.value.value.data;
@@ -117,14 +42,18 @@ argConformsToDefinition(UA_Server *server, const UA_VariableNode *argRequirement
 
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     for(size_t i = 0; i < argReqsSize; i++)
-        retval |= satisfySignature(server, &args[i], &argReqs[i]);
+        retval |= UA_Variant_matchVariableDefinition(server, &argReqs[i].dataType,
+                                                     argReqs[i].valueRank,
+                                                     argReqs[i].arrayDimensionsSize,
+                                                     argReqs[i].arrayDimensions,
+                                                     &args[i], NULL, NULL);
     return retval;
 }
 
 void
-Service_Call_single(UA_Server *server, UA_Session *session, const UA_CallMethodRequest *request,
+Service_Call_single(UA_Server *server, UA_Session *session,
+                    const UA_CallMethodRequest *request,
                     UA_CallMethodResult *result) {
-
     /* Get/verify the method node */
     const UA_MethodNode *methodCalled =
         (const UA_MethodNode*)UA_NodeStore_get(server->nodestore, &request->methodId);
@@ -153,47 +82,52 @@ Service_Call_single(UA_Server *server, UA_Session *session, const UA_CallMethodR
         return;
     }
 
-    /* Verify method/object relations. Object must have a hasComponent or a subtype of hasComponent reference to the method node. */
-    /* Therefore, check every reference between the parent object and the method node if there is a hasComponent (or subtype) reference */
+    /* Verify method/object relations. Object must have a hasComponent or a
+     * subtype of hasComponent reference to the method node. Therefore, check
+     * every reference between the parent object and the method node if there is
+     * a hasComponent (or subtype) reference */
     UA_Boolean found = false;
     UA_NodeId hasComponentNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_HASCOMPONENT);
     UA_NodeId hasSubTypeNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_HASSUBTYPE);
-    for(size_t i=0;i<methodCalled->referencesSize;i++){
-        if (methodCalled->references[i].isInverse && UA_NodeId_equal(&methodCalled->references[i].targetId.nodeId,&withObject->nodeId)){
+    for(size_t i = 0; i < methodCalled->referencesSize; i++) {
+        if(methodCalled->references[i].isInverse &&
+           UA_NodeId_equal(&methodCalled->references[i].targetId.nodeId,&withObject->nodeId)) {
             //TODO adjust maxDepth to needed tree depth (define a variable in config?)
-            isNodeInTree(server->nodestore, &methodCalled->references[i].referenceTypeId, &hasComponentNodeId,
-                 &hasSubTypeNodeId, 1, 1, &found);
-            if(found){
+            isNodeInTree(server->nodestore, &methodCalled->references[i].referenceTypeId,
+                         &hasComponentNodeId, &hasSubTypeNodeId, 1, 1, &found);
+            if(found)
                 break;
-            }
         }
     }
-    if(!found)
+    if(!found) {
         result->statusCode = UA_STATUSCODE_BADMETHODINVALID;
-    if(result->statusCode != UA_STATUSCODE_GOOD)
         return;
+    }
 
     /* Verify Input Argument count, types and sizes */
-    //check inputAgruments only if there are any
-    if(request->inputArgumentsSize > 0){
-        const UA_VariableNode *inputArguments = getArgumentsVariableNode(server, methodCalled, UA_STRING("InputArguments"));
+    const UA_VariableNode *inputArguments =
+        getArgumentsVariableNode(server, methodCalled, UA_STRING("InputArguments"));
 
-        if(!inputArguments) {
+    if(!inputArguments) {
+        if(request->inputArgumentsSize > 0) {
             result->statusCode = UA_STATUSCODE_BADINVALIDARGUMENT;
             return;
         }
-            result->statusCode = argConformsToDefinition(server, inputArguments, request->inputArgumentsSize,
-                                                     request->inputArguments);
+    } else {
+        result->statusCode = argumentsConformsToDefinition(server, inputArguments,
+                                                           request->inputArgumentsSize,
+                                                           request->inputArguments);
         if(result->statusCode != UA_STATUSCODE_GOOD)
             return;
     }
 
     /* Allocate the output arguments */
-    const UA_VariableNode *outputArguments = getArgumentsVariableNode(server, methodCalled, UA_STRING("OutputArguments"));
-    if(!outputArguments) {
-        result->outputArgumentsSize=0;
-    }else{
-        result->outputArguments = UA_Array_new(outputArguments->value.data.value.value.arrayLength, &UA_TYPES[UA_TYPES_VARIANT]);
+    result->outputArgumentsSize = 0; /* the default */
+    const UA_VariableNode *outputArguments =
+        getArgumentsVariableNode(server, methodCalled, UA_STRING("OutputArguments"));
+    if(outputArguments) {
+        result->outputArguments = UA_Array_new(outputArguments->value.data.value.value.arrayLength,
+                                               &UA_TYPES[UA_TYPES_VARIANT]);
         if(!result->outputArguments) {
             result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
             return;
@@ -201,23 +135,23 @@ Service_Call_single(UA_Server *server, UA_Session *session, const UA_CallMethodR
         result->outputArgumentsSize = outputArguments->value.data.value.value.arrayLength;
     }
 
+    /* Call the method */
 #if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
     methodCallSession = session;
 #endif
-
-    /* Call the method */
     result->statusCode = methodCalled->attachedMethod(methodCalled->methodHandle, withObject->nodeId,
                                                       request->inputArgumentsSize, request->inputArguments,
                                                       result->outputArgumentsSize, result->outputArguments);
-
 #if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
     methodCallSession = NULL;
 #endif
-    /* TODO: Verify Output Argument count, types and sizes */
+
+    /* TODO: Verify Output matches the argument definition */
 }
-void Service_Call(UA_Server *server, UA_Session *session, const UA_CallRequest *request,
-                  UA_CallResponse *response) {
 
+void Service_Call(UA_Server *server, UA_Session *session,
+                  const UA_CallRequest *request,
+                  UA_CallResponse *response) {
     UA_LOG_DEBUG_SESSION(server->config.logger, session, "Processing CallRequest");
     if(request->methodsToCallSize <= 0) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;

+ 3 - 13
src/server/ua_services_nodemanagement.c

@@ -568,26 +568,16 @@ static UA_StatusCode
 copyCommonVariableAttributes(UA_Server *server, UA_VariableNode *node,
                              const UA_AddNodesItem *item,
                              const UA_VariableAttributes *attr) {
-
-    /* Use datatype of the typedefiniton or BaseDataType */
-    UA_NodeId dataType = attr->dataType;
-    if(UA_NodeId_isNull(&dataType)) {
-        const UA_DataType *found = findDataType(&item->typeDefinition.nodeId);
-        if(found)
-            dataType = found->typeId;
-        dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE);
-    }
-    
-    // todo: test if the type / valueRank / value attributes are consistent
+    /* Set the constraints */
     UA_StatusCode retval = UA_Array_copy(attr->arrayDimensions, attr->arrayDimensionsSize,
                                          (void**)&node->arrayDimensions, &UA_TYPES[UA_TYPES_INT32]);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
     node->arrayDimensionsSize = attr->arrayDimensionsSize;
-    retval = UA_NodeId_copy(&dataType, &node->dataType);
+    retval = UA_NodeId_copy(&attr->dataType, &node->dataType);
     node->valueRank = attr->valueRank;
 
-    /* Set the value */
+    /* Set the value with the write service. This also checks the constraints. */
     UA_DataValue value;
     UA_DataValue_init(&value);
     value.value = attr->value;

+ 2 - 6
src/ua_types.c

@@ -419,12 +419,8 @@ computeStrides(const UA_Variant *v, const UA_NumericRange range,
     if(v->arrayDimensionsSize > 0) {
         dims_count = v->arrayDimensionsSize;
         dims = (UA_UInt32*)v->arrayDimensions;
-        for(size_t i = 0; i < dims_count; i++) {
-            /* dimensions can have negative size similar to array lengths */
-            if(v->arrayDimensions[i] < 0)
-                return UA_STATUSCODE_BADINDEXRANGEINVALID;
+        for(size_t i = 0; i < dims_count; i++)
             elements *= dims[i];
-        }
         if(elements != v->arrayLength)
             return UA_STATUSCODE_BADINTERNALERROR;
     }
@@ -611,7 +607,7 @@ UA_Variant_copyRange(const UA_Variant *orig_src, UA_Variant *dst,
         dst->arrayDimensionsSize = thisrange.dimensionsSize;
         for(size_t k = 0; k < thisrange.dimensionsSize; k++)
             dst->arrayDimensions[k] =
-                (UA_Int32)(thisrange.dimensions[k].max - thisrange.dimensions[k].min + 1);
+                thisrange.dimensions[k].max - thisrange.dimensions[k].min + 1;
     }
     return UA_STATUSCODE_GOOD;
 }

+ 1 - 1
tests/check_services_attributes.c

@@ -73,7 +73,7 @@ static UA_Server* makeTestSequence(void) {
     UA_VariableAttributes_init(&vattr);
     UA_Int32 myIntegerArray[9] = {1,2,3,4,5,6,7,8,9};
     UA_Variant_setArray(&vattr.value, &myIntegerArray, 9, &UA_TYPES[UA_TYPES_INT32]);
-    UA_Int32 myIntegerDimensions[2] = {3,3};
+    UA_UInt32 myIntegerDimensions[2] = {3,3};
     vattr.value.arrayDimensions = myIntegerDimensions;
     vattr.value.arrayDimensionsSize = 2;
     vattr.displayName = UA_LOCALIZEDTEXT("locale","myarray");

+ 4 - 4
tests/check_types_builtin.c

@@ -1322,7 +1322,7 @@ START_TEST(UA_Variant_copyShallWorkOn1DArrayExample) {
     srcArray[1] = UA_STRING_ALLOC("_62541");
     srcArray[2] = UA_STRING_ALLOC("opc ua");
 
-    UA_Int32 *dimensions;
+    UA_UInt32 *dimensions;
     dimensions = UA_malloc(sizeof(UA_Int32));
     dimensions[0] = 3;
 
@@ -1373,9 +1373,9 @@ START_TEST(UA_Variant_copyShallWorkOn2DArrayExample) {
     srcArray[4] = 4;
     srcArray[5] = 5;
 
-    UA_Int32 *dimensions = UA_Array_new(2, &UA_TYPES[UA_TYPES_INT32]);
-    UA_Int32 dim1 = 3;
-    UA_Int32 dim2 = 2;
+    UA_UInt32 *dimensions = UA_Array_new(2, &UA_TYPES[UA_TYPES_INT32]);
+    UA_UInt32 dim1 = 3;
+    UA_UInt32 dim2 = 2;
     dimensions[0] = dim1;
     dimensions[1] = dim2;