Browse Source

don't copy data for reading. use a NODELETE variant that points into the node

Julius Pfrommer 9 years ago
parent
commit
c33b62c682

+ 2 - 3
examples/networklayer_tcp.c

@@ -86,7 +86,7 @@ static UA_StatusCode
 socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeout) {
     response->data = malloc(connection->localConf.recvBufferSize);
     if(!response->data) {
-        response->length = -1;
+        response->length = 0;
         return UA_STATUSCODE_BADOUTOFMEMORY; /* not enough memory retry */
     }
 
@@ -296,8 +296,7 @@ static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer, U
          .sin_port = htons(layer->port), .sin_zero = {0}};
     int optval = 1;
     if(setsockopt(layer->serversockfd, SOL_SOCKET,
-                  SO_REUSEADDR, (const char *)&optval,
-                  sizeof(optval)) == -1) {
+                  SO_REUSEADDR, (const char *)&optval, sizeof(optval)) == -1) {
         UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_NETWORK,
                        "Error during setting of socket options");
         CLOSESOCKET(layer->serversockfd);

+ 11 - 24
examples/server.c

@@ -54,17 +54,12 @@ readTimeData(void *handle, const UA_NodeId nodeId, UA_Boolean sourceTimeStamp,
         value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
         return UA_STATUSCODE_GOOD;
     }
-	UA_DateTime *currentTime = UA_DateTime_new();
-	if(!currentTime)
-		return UA_STATUSCODE_BADOUTOFMEMORY;
-	*currentTime = UA_DateTime_now();
-	value->value.type = &UA_TYPES[UA_TYPES_DATETIME];
-	value->value.arrayLength = -1;
-	value->value.data = currentTime;
+	UA_DateTime currentTime = UA_DateTime_now();
+    UA_Variant_setScalarCopy(&value->value, &currentTime, &UA_TYPES[UA_TYPES_DATETIME]);
 	value->hasValue = UA_TRUE;
 	if(sourceTimeStamp) {
 		value->hasSourceTimestamp = UA_TRUE;
-		value->sourceTimestamp = *currentTime;
+		value->sourceTimestamp = currentTime;
 	}
 	return UA_STATUSCODE_GOOD;
 }
@@ -83,28 +78,20 @@ readTemperature(void *handle, const UA_NodeId nodeId, UA_Boolean sourceTimeStamp
         return UA_STATUSCODE_GOOD;
     }
 
-	UA_Double* currentTemperature = UA_Double_new();
-
-	if(!currentTemperature)
-		return UA_STATUSCODE_BADOUTOFMEMORY;
-
 	rewind(temperatureFile);
 	fflush(temperatureFile);
 
-	if(fscanf(temperatureFile, "%lf", currentTemperature) != 1){
+	UA_Double currentTemperature;
+	if(fscanf(temperatureFile, "%lf", &currentTemperature) != 1){
 		UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND, "Can not parse temperature");
 		exit(1);
 	}
 
-	*currentTemperature /= 1000.0;
+	currentTemperature /= 1000.0;
 
 	value->sourceTimestamp = UA_DateTime_now();
 	value->hasSourceTimestamp = UA_TRUE;
-	value->value.type = &UA_TYPES[UA_TYPES_DOUBLE];
-	value->value.arrayLength = -1;
-	value->value.data = currentTemperature;
-	value->value.arrayDimensionsSize = -1;
-	value->value.arrayDimensions = NULL;
+    UA_Variant_setScalarCopy(&value->value, &currentTemperature, &UA_TYPES[UA_TYPES_DOUBLE]);
 	value->hasValue = UA_TRUE;
 	return UA_STATUSCODE_GOOD;
 }
@@ -385,21 +372,21 @@ int main(int argc, char** argv) {
 #ifdef ENABLE_METHODCALLS
     UA_Argument inputArguments;
     UA_Argument_init(&inputArguments);
-    inputArguments.arrayDimensionsSize = -1;
+    inputArguments.arrayDimensionsSize = 0;
     inputArguments.arrayDimensions = NULL;
     inputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     inputArguments.description = UA_LOCALIZEDTEXT("en_US", "A String");
     inputArguments.name = UA_STRING("Input an integer");
-    inputArguments.valueRank = -1;
+    inputArguments.valueRank = 0;
 
     UA_Argument outputArguments;
     UA_Argument_init(&outputArguments);
-    outputArguments.arrayDimensionsSize = -1;
+    outputArguments.arrayDimensionsSize = 0;
     outputArguments.arrayDimensions = NULL;
     outputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     outputArguments.description = UA_LOCALIZEDTEXT("en_US", "A String");
     outputArguments.name = UA_STRING("Input an integer");
-    outputArguments.valueRank = -1;
+    outputArguments.valueRank = 0;
 
     UA_MethodAttributes addmethodattributes;
     UA_MethodAttributes_init(&addmethodattributes);

+ 1 - 1
examples/server_readspeed.c

@@ -74,7 +74,7 @@ int main(int argc, char** argv) {
     UA_ReadRequest rq;
     UA_ReadResponse rr;
 
-    for(int i = 0; i < 750000; i++) {
+    for(int i = 0; i < 900000; i++) {
         offset = 0;
         retval |= UA_decodeBinary(&request_msg, &offset, &rq, &UA_TYPES[UA_TYPES_READREQUEST]);
 

+ 0 - 4
include/ua_server.h

@@ -404,10 +404,6 @@ static UA_INLINE UA_StatusCode
 UA_Server_writeValueAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_Variant value) {
     return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_VALUE, &UA_TYPES[UA_TYPES_VARIANT], &value); }
 
-/* The value content is moved into the node (not copied). The input variant is _inited internally. */
-UA_StatusCode UA_EXPORT
-UA_Server_writeValueAttribute_move(UA_Server *server, const UA_NodeId nodeId, UA_Variant *value);
-
 static UA_INLINE UA_StatusCode
 UA_Server_writeAccessLevelAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_UInt32 accessLevel) {
     return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, &UA_TYPES[UA_TYPES_UINT32], &accessLevel); }

+ 2 - 4
include/ua_types.h

@@ -364,9 +364,8 @@ static UA_INLINE UA_Boolean UA_Variant_isScalar(const UA_Variant *v) {
  * @param v The variant
  * @param p A pointer to the value data
  * @param type The datatype of the value in question
- * @return Indicates whether the operation succeeded or returns an error code
  */
-UA_StatusCode UA_EXPORT UA_Variant_setScalar(UA_Variant *v, void * UA_RESTRICT p, const UA_DataType *type);
+void UA_EXPORT UA_Variant_setScalar(UA_Variant *v, void * UA_RESTRICT p, const UA_DataType *type);
 
 /**
  * Set the variant to a scalar value that is copied from an existing variable.
@@ -386,9 +385,8 @@ UA_StatusCode UA_EXPORT UA_Variant_setScalarCopy(UA_Variant *v, const void *p, c
  * @param array A pointer to the array data
  * @param arraySize The size of the array
  * @param type The datatype of the array
- * @return Indicates whether the operation succeeded or returns an error code
  */
-UA_StatusCode UA_EXPORT
+void UA_EXPORT
 UA_Variant_setArray(UA_Variant *v, void * UA_RESTRICT array, size_t arraySize, const UA_DataType *type);
 
 /**

+ 16 - 40
src/server/ua_server.c

@@ -193,34 +193,26 @@ __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
                     const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
                     const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
                     const UA_DataType *attributeType, UA_NodeId *outNewNodeId) {
+    const UA_AddNodesItem item = (const UA_AddNodesItem){
+        .parentNodeId = (UA_ExpandedNodeId){.nodeId = parentNodeId, .namespaceUri = UA_STRING_NULL,
+                                            .serverIndex = 0},
+        .referenceTypeId = referenceTypeId, .requestedNewNodeId = requestedNewNodeId,
+        .browseName = browseName, .nodeClass = nodeClass,
+        .typeDefinition = (UA_ExpandedNodeId){.nodeId = typeDefinition, .namespaceUri = UA_STRING_NULL,
+                                              .serverIndex = 0},
+        .nodeAttributes = {.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE,
+                           .content.decoded.type = attributeType,
+                           .content.decoded.data = (void*)(uintptr_t)attr}};
     UA_AddNodesResult result;
     UA_AddNodesResult_init(&result);
-
-    UA_AddNodesItem item;
-    UA_AddNodesItem_init(&item);
-    result.statusCode = UA_QualifiedName_copy(&browseName, &item.browseName);
-    item.nodeClass = nodeClass;
-    result.statusCode |= UA_NodeId_copy(&parentNodeId, &item.parentNodeId.nodeId);
-    result.statusCode |= UA_NodeId_copy(&referenceTypeId, &item.referenceTypeId);
-    result.statusCode |= UA_NodeId_copy(&requestedNewNodeId,
-                                        &item.requestedNewNodeId.nodeId);
-    result.statusCode |= UA_NodeId_copy(&typeDefinition, &item.typeDefinition.nodeId);
-    UA_NodeAttributes *attrCopy;
-    result.statusCode |= UA_Array_copy(attr, 1, (void**)&attrCopy, attributeType);
-    item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED;
-    item.nodeAttributes.content.decoded.type = attributeType;
-    item.nodeAttributes.content.decoded.data = attrCopy;
-    if(result.statusCode == UA_STATUSCODE_GOOD) {
-        UA_RCU_LOCK();
-        Service_AddNodes_single(server, &adminSession, &item, &result);
-        UA_RCU_UNLOCK();
-    }
+    UA_RCU_LOCK();
+    Service_AddNodes_single(server, &adminSession, &item, &result);
+    UA_RCU_UNLOCK();
 
     if(outNewNodeId && result.statusCode == UA_STATUSCODE_GOOD)
         *outNewNodeId = result.addedNodeId;
     else
         UA_AddNodesResult_deleteMembers(&result);
-    UA_AddNodesItem_deleteMembers(&item);
     return result.statusCode;
 }
 
@@ -1206,28 +1198,12 @@ __UA_Server_writeAttribute(UA_Server *server, const UA_NodeId nodeId,
     wvalue.nodeId = nodeId;
     wvalue.attributeId = attributeId;
     if(attributeId != UA_ATTRIBUTEID_VALUE)
-        UA_Variant_setScalarCopy(&wvalue.value.value, value, type);
+        /* hacked cast. the target WriteValue is used as const anyway */
+        UA_Variant_setScalar(&wvalue.value.value, (void*)(uintptr_t)value, type);
     else
-        UA_Variant_copy(value, &wvalue.value.value);
-    wvalue.value.hasValue = UA_TRUE;
-    UA_StatusCode retval = Service_Write_single(server, &adminSession, &wvalue);
-    UA_NodeId_init(&wvalue.nodeId);
-    UA_WriteValue_deleteMembers(&wvalue);
-    return retval;
-}
-
-UA_StatusCode
-UA_Server_writeValueAttribute_move(UA_Server *server, const UA_NodeId nodeId, UA_Variant *value) {
-    UA_WriteValue wvalue;
-    UA_WriteValue_init(&wvalue);
-    wvalue.nodeId = nodeId;
-    wvalue.attributeId = UA_ATTRIBUTEID_VALUE;
-    wvalue.value.value = *value;
-    UA_Variant_init(value);
+        wvalue.value.value = *(const UA_Variant*)value;
     wvalue.value.hasValue = UA_TRUE;
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wvalue);
-    UA_NodeId_init(&wvalue.nodeId);
-    UA_WriteValue_deleteMembers(&wvalue);
     return retval;
 }
 

+ 4 - 4
src/server/ua_server_binary.c

@@ -222,12 +222,12 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     UA_SequenceHeader sequenceHeader;
     retval = UA_UInt32_decodeBinary(msg, pos, &tokenId);
     retval |= UA_SequenceHeader_decodeBinary(msg, pos, &sequenceHeader);
-#ifndef EXTENSION_STATELESS
-    if(retval != UA_STATUSCODE_GOOD || tokenId == 0) // 0 is invalid
-        return;
-#else
     if(retval != UA_STATUSCODE_GOOD)
         return;
+
+#ifndef EXTENSION_STATELESS
+    if(tokenId == 0) // 0 is invalid
+        return;
 #endif
 
     if(clientChannel != &anonymousChannel && tokenId != clientChannel->securityToken.tokenId) {

+ 2 - 2
src/server/ua_services.h

@@ -107,7 +107,7 @@ void Service_CloseSession(UA_Server *server, UA_Session *session, const UA_Close
 /** Used to add one or more Nodes into the AddressSpace hierarchy. */
 void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesRequest *request,
                       UA_AddNodesResponse *response);
-void Service_AddNodes_single(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
+void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
                              UA_AddNodesResult *result);
 
 /** Used to add one or more References to one or more Nodes. */
@@ -227,7 +227,7 @@ void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest
                    UA_WriteResponse *response);
 
 /** Single attribute writes are exposed to the userspace. The wvalue may be destroyed (deleteMembers) */
-UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session, UA_WriteValue *wvalue);
+UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session, const UA_WriteValue *wvalue);
 
 // Service_HistoryUpdate
 /** @} */

+ 79 - 71
src/server/ua_services_attribute.c

@@ -103,6 +103,15 @@ static void handleSourceTimestamps(UA_TimestampsToReturn timestamps, UA_DataValu
 	}
 }
 
+/* force cast for zero-copy reading. ensure that the variant is never written into. */
+static void forceVariantSetScalar(UA_Variant *v, const void *p, const UA_DataType *type) {
+    UA_Variant_init(v);
+    v->type = type;
+    v->arrayLength = 0;
+    v->data = (void*)(uintptr_t)p;
+    v->storageType = UA_VARIANT_DATA_NODELETE;
+}
+
 static UA_StatusCode getVariableNodeValue(const UA_VariableNode *vn, const UA_TimestampsToReturn timestamps,
                                           const UA_ReadValueId *id, UA_DataValue *v) {
     UA_NumericRange range;
@@ -119,10 +128,11 @@ static UA_StatusCode getVariableNodeValue(const UA_VariableNode *vn, const UA_Ti
         if(vn->value.variant.callback.onRead)
             vn->value.variant.callback.onRead(vn->value.variant.callback.handle, vn->nodeId,
                                               &v->value, rangeptr);
-        if(rangeptr)
+        if(!rangeptr) {
+            v->value = vn->value.variant.value;
+            v->value.storageType = UA_VARIANT_DATA_NODELETE;
+        } else
             retval = UA_Variant_copyRange(&vn->value.variant.value, &v->value, range);
-        else
-            retval = UA_Variant_copy(&vn->value.variant.value, &v->value);
         if(retval == UA_STATUSCODE_GOOD)
             handleSourceTimestamps(timestamps, v);
     } else {
@@ -140,8 +150,8 @@ static UA_StatusCode getVariableNodeValue(const UA_VariableNode *vn, const UA_Ti
 static UA_StatusCode getVariableNodeDataType(const UA_VariableNode *vn, UA_DataValue *v) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
-        retval = UA_Variant_setScalarCopy(&v->value, &vn->value.variant.value.type->typeId,
-                                          &UA_TYPES[UA_TYPES_NODEID]);
+        forceVariantSetScalar(&v->value, &vn->value.variant.value.type->typeId,
+                              &UA_TYPES[UA_TYPES_NODEID]);
     } else {
         /* Read from the datasource to see the data type */
         UA_DataValue val;
@@ -158,8 +168,9 @@ static UA_StatusCode getVariableNodeDataType(const UA_VariableNode *vn, UA_DataV
 static UA_StatusCode getVariableNodeArrayDimensions(const UA_VariableNode *vn, UA_DataValue *v) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
-        retval = UA_Variant_setArrayCopy(&v->value, vn->value.variant.value.arrayDimensions,
-                                         vn->value.variant.value.arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
+        UA_Variant_setArray(&v->value, vn->value.variant.value.arrayDimensions,
+                            vn->value.variant.value.arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
+        v->value.storageType = UA_VARIANT_DATA_NODELETE;
     } else {
         /* Read the datasource to see the array dimensions */
         UA_DataValue val;
@@ -204,54 +215,53 @@ void Service_Read_single(UA_Server *server, UA_Session *session, const UA_Timest
     /* When setting the value fails in the switch, we get an error code and set hasValue to false */
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     v->hasValue = UA_TRUE;
-
     switch(id->attributeId) {
     case UA_ATTRIBUTEID_NODEID:
-        retval = UA_Variant_setScalarCopy(&v->value, &node->nodeId, &UA_TYPES[UA_TYPES_NODEID]);
+        forceVariantSetScalar(&v->value, &node->nodeId, &UA_TYPES[UA_TYPES_NODEID]);
         break;
     case UA_ATTRIBUTEID_NODECLASS:
-        retval = UA_Variant_setScalarCopy(&v->value, &node->nodeClass, &UA_TYPES[UA_TYPES_INT32]);
+        forceVariantSetScalar(&v->value, &node->nodeClass, &UA_TYPES[UA_TYPES_INT32]);
         break;
     case UA_ATTRIBUTEID_BROWSENAME:
-        retval = UA_Variant_setScalarCopy(&v->value, &node->browseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
+        forceVariantSetScalar(&v->value, &node->browseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
         break;
     case UA_ATTRIBUTEID_DISPLAYNAME:
-        retval = UA_Variant_setScalarCopy(&v->value, &node->displayName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+        forceVariantSetScalar(&v->value, &node->displayName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
         break;
     case UA_ATTRIBUTEID_DESCRIPTION:
-        retval = UA_Variant_setScalarCopy(&v->value, &node->description, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+        forceVariantSetScalar(&v->value, &node->description, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
         break;
     case UA_ATTRIBUTEID_WRITEMASK:
-        retval = UA_Variant_setScalarCopy(&v->value, &node->writeMask, &UA_TYPES[UA_TYPES_UINT32]);
+        forceVariantSetScalar(&v->value, &node->writeMask, &UA_TYPES[UA_TYPES_UINT32]);
         break;
     case UA_ATTRIBUTEID_USERWRITEMASK:
-        retval = UA_Variant_setScalarCopy(&v->value, &node->userWriteMask, &UA_TYPES[UA_TYPES_UINT32]);
+        forceVariantSetScalar(&v->value, &node->userWriteMask, &UA_TYPES[UA_TYPES_UINT32]);
         break;
     case UA_ATTRIBUTEID_ISABSTRACT:
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE | UA_NODECLASS_OBJECTTYPE |
                         UA_NODECLASS_VARIABLETYPE | UA_NODECLASS_DATATYPE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode*)node)->isAbstract,
-                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
+        forceVariantSetScalar(&v->value, &((const UA_ReferenceTypeNode*)node)->isAbstract,
+                              &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
     case UA_ATTRIBUTEID_SYMMETRIC:
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode*)node)->symmetric,
-                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
+        forceVariantSetScalar(&v->value, &((const UA_ReferenceTypeNode*)node)->symmetric,
+                              &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
     case UA_ATTRIBUTEID_INVERSENAME:
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode*)node)->inverseName,
-                                          &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+        forceVariantSetScalar(&v->value, &((const UA_ReferenceTypeNode*)node)->inverseName,
+                              &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
         break;
     case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
         CHECK_NODECLASS(UA_NODECLASS_VIEW);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ViewNode*)node)->containsNoLoops,
-                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
+        forceVariantSetScalar(&v->value, &((const UA_ViewNode*)node)->containsNoLoops,
+                              &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
     case UA_ATTRIBUTEID_EVENTNOTIFIER:
         CHECK_NODECLASS(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ViewNode*)node)->eventNotifier,
-                                          &UA_TYPES[UA_TYPES_BYTE]);
+        forceVariantSetScalar(&v->value, &((const UA_ViewNode*)node)->eventNotifier,
+                              &UA_TYPES[UA_TYPES_BYTE]);
         break;
     case UA_ATTRIBUTEID_VALUE:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
@@ -263,8 +273,8 @@ void Service_Read_single(UA_Server *server, UA_Session *session, const UA_Timest
         break;
     case UA_ATTRIBUTEID_VALUERANK:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableTypeNode*)node)->valueRank,
-                                           &UA_TYPES[UA_TYPES_INT32]);
+        forceVariantSetScalar(&v->value, &((const UA_VariableTypeNode*)node)->valueRank,
+                              &UA_TYPES[UA_TYPES_INT32]);
         break;
     case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
@@ -272,33 +282,33 @@ void Service_Read_single(UA_Server *server, UA_Session *session, const UA_Timest
         break;
     case UA_ATTRIBUTEID_ACCESSLEVEL:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode*)node)->accessLevel,
-                                          &UA_TYPES[UA_TYPES_BYTE]);
+        forceVariantSetScalar(&v->value, &((const UA_VariableNode*)node)->accessLevel,
+                              &UA_TYPES[UA_TYPES_BYTE]);
         break;
     case UA_ATTRIBUTEID_USERACCESSLEVEL:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode*)node)->userAccessLevel,
-                                          &UA_TYPES[UA_TYPES_BYTE]);
+        forceVariantSetScalar(&v->value, &((const UA_VariableNode*)node)->userAccessLevel,
+                              &UA_TYPES[UA_TYPES_BYTE]);
         break;
     case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode*)node)->minimumSamplingInterval,
-                                          &UA_TYPES[UA_TYPES_DOUBLE]);
+        forceVariantSetScalar(&v->value, &((const UA_VariableNode*)node)->minimumSamplingInterval,
+                              &UA_TYPES[UA_TYPES_DOUBLE]);
         break;
     case UA_ATTRIBUTEID_HISTORIZING:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode*)node)->historizing,
-                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
+        forceVariantSetScalar(&v->value, &((const UA_VariableNode*)node)->historizing,
+                              &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
     case UA_ATTRIBUTEID_EXECUTABLE:
         CHECK_NODECLASS(UA_NODECLASS_METHOD);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_MethodNode*)node)->executable,
-                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
+        forceVariantSetScalar(&v->value, &((const UA_MethodNode*)node)->executable,
+                              &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
     case UA_ATTRIBUTEID_USEREXECUTABLE:
         CHECK_NODECLASS(UA_NODECLASS_METHOD);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_MethodNode*)node)->userExecutable,
-                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
+        forceVariantSetScalar(&v->value, &((const UA_MethodNode*)node)->userExecutable,
+                              &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
     default:
         retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
@@ -373,8 +383,8 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
     }
 
 #ifdef EXTENSION_STATELESS
+    /* Add an expiry header for caching */
     if(session==&anonymousSession){
-		/* expiry header */
 		UA_ExtensionObject additionalHeader;
 		UA_ExtensionObject_init(&additionalHeader);
 		additionalHeader.typeId = UA_TYPES[UA_TYPES_VARIANT].typeId;
@@ -415,11 +425,11 @@ UA_StatusCode UA_Server_editNode(UA_Server *server, UA_Session *session, const U
                                  UA_EditNodeCallback callback, const void *data) {
     UA_StatusCode retval;
     do {
-        const UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
+        UA_MT_CONST UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
         if(!node)
             return UA_STATUSCODE_BADNODEIDUNKNOWN;
 #ifndef UA_MULTITHREADING
-        retval = callback(server, session, (UA_Node*)(uintptr_t)node, data);
+        retval = callback(server, session, node, data);
         return retval;
 #else
         UA_Node *copy = UA_Node_copyAnyNodeClass(node);
@@ -454,7 +464,7 @@ UA_StatusCode UA_Server_editNode(UA_Server *server, UA_Session *session, const U
 
 static UA_StatusCode
 Service_Write_single_ValueDataSource(UA_Server *server, UA_Session *session, const UA_VariableNode *node,
-                                     UA_WriteValue *wvalue) {
+                                     const UA_WriteValue *wvalue) {
     UA_assert(wvalue->attributeId == UA_ATTRIBUTEID_VALUE);
     UA_assert(node->nodeClass == UA_NODECLASS_VARIABLE || node->nodeClass == UA_NODECLASS_VARIABLETYPE);
     UA_assert(node->valueSource == UA_VALUESOURCE_DATASOURCE);
@@ -493,7 +503,7 @@ static enum type_equivalence typeEquivalence(const UA_DataType *type) {
 
 /* In the multithreaded case, node is a copy */
 static UA_StatusCode
-MoveValueIntoNode(UA_Server *server, UA_Session *session, UA_VariableNode *node, UA_WriteValue *wvalue) {
+CopyValueIntoNode(UA_VariableNode *node, const UA_WriteValue *wvalue) {
     UA_assert(wvalue->attributeId == UA_ATTRIBUTEID_VALUE);
     UA_assert(node->nodeClass == UA_NODECLASS_VARIABLE || node->nodeClass == UA_NODECLASS_VARIABLETYPE);
     UA_assert(node->valueSource == UA_VALUESOURCE_VARIANT);
@@ -511,7 +521,7 @@ MoveValueIntoNode(UA_Server *server, UA_Session *session, UA_VariableNode *node,
 
     /* The nodeid on the wire may be != the nodeid in the node: opaque types, enums and bytestrings.
        nodeV contains the correct type definition. */
-    UA_Variant *newV = &wvalue->value.value;
+    const UA_Variant *newV = &wvalue->value.value;
     UA_Variant *oldV = &node->value.variant.value;
     UA_Variant cast_v;
     if(!UA_NodeId_equal(&oldV->type->typeId, &newV->type->typeId)) {
@@ -522,14 +532,14 @@ MoveValueIntoNode(UA_Server *server, UA_Session *session, UA_VariableNode *node,
         if(te1 != TYPE_EQUIVALENCE_NONE && te1 == te2) {
             /* An enum was sent as an int32, or an opaque type as a bytestring. This is
                detected with the typeIndex indicated the "true" datatype. */
-            newV->type = oldV->type;
+            cast_v.type = oldV->type;
         } else if(oldV->type == &UA_TYPES[UA_TYPES_BYTE] && !UA_Variant_isScalar(oldV) &&
                   newV->type == &UA_TYPES[UA_TYPES_BYTESTRING] && UA_Variant_isScalar(newV)) {
             /* a string is written to a byte array */
             UA_ByteString *str = (UA_ByteString*) newV->data;
-            newV->arrayLength = str->length;
-            newV->data = str->data;
-            newV->type = &UA_TYPES[UA_TYPES_BYTE];
+            cast_v.arrayLength = str->length;
+            cast_v.data = str->data;
+            cast_v.type = &UA_TYPES[UA_TYPES_BYTE];
         } else {
             if(rangeptr)
                 UA_free(range.dimensions);
@@ -538,13 +548,10 @@ MoveValueIntoNode(UA_Server *server, UA_Session *session, UA_VariableNode *node,
     }
     
     if(!rangeptr) {
-        // TODO: Avoid copying the whole node and then delete the old value for multithreading
         UA_Variant_deleteMembers(&node->value.variant.value);
-        node->value.variant.value = *newV;
-        UA_Variant_init(&wvalue->value.value);
-    } else {
+        UA_Variant_copy(newV, &node->value.variant.value);
+    } else
         retval = UA_Variant_setRangeCopy(&node->value.variant.value, newV->data, newV->arrayLength, range);
-    }
     if(node->value.variant.callback.onWrite)
         node->value.variant.callback.onWrite(node->value.variant.callback.handle, node->nodeId,
                                              &node->value.variant.value, rangeptr);
@@ -554,9 +561,11 @@ MoveValueIntoNode(UA_Server *server, UA_Session *session, UA_VariableNode *node,
 }
 
 static UA_StatusCode
-MoveAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, UA_WriteValue *wvalue) {
+CopyAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, const UA_WriteValue *wvalue) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     void *value = wvalue->value.value.data;
+    void *target;
+    const UA_DataType *type = NULL;
 	switch(wvalue->attributeId) {
     case UA_ATTRIBUTEID_NODEID:
     case UA_ATTRIBUTEID_NODECLASS:
@@ -565,21 +574,18 @@ MoveAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, UA_
 		break;
 	case UA_ATTRIBUTEID_BROWSENAME:
 		CHECK_DATATYPE(QUALIFIEDNAME);
-		UA_QualifiedName_deleteMembers(&node->browseName);
-        node->browseName = *(UA_QualifiedName*)value;
-        UA_QualifiedName_init((UA_QualifiedName*)value);
+        target = &node->browseName;
+        type = &UA_TYPES[UA_TYPES_QUALIFIEDNAME];
 		break;
 	case UA_ATTRIBUTEID_DISPLAYNAME:
 		CHECK_DATATYPE(LOCALIZEDTEXT);
-		UA_LocalizedText_deleteMembers(&node->displayName);
-        node->displayName = *(UA_LocalizedText*)value;
-		UA_LocalizedText_init((UA_LocalizedText*)value);
+        target = &node->displayName;
+        type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
 		break;
 	case UA_ATTRIBUTEID_DESCRIPTION:
 		CHECK_DATATYPE(LOCALIZEDTEXT);
-		UA_LocalizedText_deleteMembers(&node->description);
-        node->description = *(UA_LocalizedText*)value;
-		UA_LocalizedText_init((UA_LocalizedText*)value);
+        target = &node->description;
+        type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
 		break;
 	case UA_ATTRIBUTEID_WRITEMASK:
 		CHECK_DATATYPE(UINT32);
@@ -603,10 +609,8 @@ MoveAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, UA_
 	case UA_ATTRIBUTEID_INVERSENAME:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE);
 		CHECK_DATATYPE(LOCALIZEDTEXT);
-        UA_ReferenceTypeNode *n = (UA_ReferenceTypeNode*)node;
-		UA_LocalizedText_deleteMembers(&n->inverseName);
-        n->inverseName = *(UA_LocalizedText*)value;
-		UA_LocalizedText_init((UA_LocalizedText*)value);
+        target = &((UA_ReferenceTypeNode*)node)->inverseName;
+        type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
 		break;
 	case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW);
@@ -620,7 +624,7 @@ MoveAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, UA_
 		break;
 	case UA_ATTRIBUTEID_VALUE:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        retval = MoveValueIntoNode(server, session, (UA_VariableNode*)node, wvalue);
+        retval = CopyValueIntoNode((UA_VariableNode*)node, wvalue);
 		break;
 	case UA_ATTRIBUTEID_ACCESSLEVEL:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
@@ -656,10 +660,14 @@ MoveAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, UA_
 		retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
 		break;
 	}
+    if(type) {
+        UA_deleteMembers(target, type);
+        retval = UA_copy(value, target, type);
+    }
     return retval;
 }
 
-UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session, UA_WriteValue *wvalue) {
+UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session, const UA_WriteValue *wvalue) {
     if(!wvalue->value.hasValue || !wvalue->value.value.data)
         return UA_STATUSCODE_BADNODATA; // TODO: is this the right return code?
     if(wvalue->attributeId == UA_ATTRIBUTEID_VALUE) {
@@ -674,7 +682,7 @@ UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session, UA_Wr
         }
     }
     return UA_Server_editNode(server, session, &wvalue->nodeId,
-                              (UA_EditNodeCallback)MoveAttributeIntoNode, wvalue);
+                              (UA_EditNodeCallback)CopyAttributeIntoNode, wvalue);
 }
 
 void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest *request,

+ 59 - 35
src/server/ua_services_nodemanagement.c

@@ -65,16 +65,16 @@ UA_Server_addExistingNode(UA_Server *server, UA_Session *session, UA_Node *node,
             return;
         }
     }
+    /* Careful. The node is inserted. If the nodestore makes an expand, nodes change their address */
     
     // reference back to the parent
     UA_AddReferencesItem item;
     UA_AddReferencesItem_init(&item);
     item.sourceNodeId = managed->nodeId;
-    item.referenceTypeId = referenceType->nodeId;
+    item.referenceTypeId = *referenceTypeId;
     item.isForward = UA_FALSE;
-    item.targetNodeId.nodeId = parent->nodeId;
+    item.targetNodeId.nodeId = *parentNodeId;
     Service_AddReferences_single(server, session, &item);
-
     // todo: error handling. remove new node from nodestore
 }
 
@@ -310,106 +310,130 @@ instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId
     return UA_STATUSCODE_GOOD;
 }
 
-static void moveStandardAttributes(UA_Node *node, UA_AddNodesItem *item, UA_NodeAttributes *attr) {
-    node->nodeId = item->requestedNewNodeId.nodeId;
-    UA_NodeId_init(&item->requestedNewNodeId.nodeId);
-    node->browseName = item->browseName;
-    UA_QualifiedName_init(&item->browseName);
-    node->displayName = attr->displayName;
-    UA_LocalizedText_init(&attr->displayName);
-    node->description = attr->description;
-    UA_LocalizedText_init(&attr->description);
+static UA_StatusCode
+copyStandardAttributes(UA_Node *node, const UA_AddNodesItem *item, const UA_NodeAttributes *attr) {
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    retval |= UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId);
+    retval |= UA_QualifiedName_copy(&item->browseName, &node->browseName);
+    retval |= UA_LocalizedText_copy(&attr->displayName, &node->displayName);
+    retval |= UA_LocalizedText_copy(&attr->description, &node->description);
     node->writeMask = attr->writeMask;
     node->userWriteMask = attr->userWriteMask;
+    return retval;
 }
 
 static UA_Node *
-variableNodeFromAttributes(UA_AddNodesItem *item, UA_VariableAttributes *attr) {
+variableNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableAttributes *attr) {
     UA_VariableNode *vnode = UA_VariableNode_new();
     if(!vnode)
         return NULL;
-    moveStandardAttributes((UA_Node*)vnode, item, (UA_NodeAttributes*)attr);
+    UA_StatusCode retval = copyStandardAttributes((UA_Node*)vnode, item, (const UA_NodeAttributes*)attr);
     // todo: test if the type / valueRank / value attributes are consistent
     vnode->accessLevel = attr->accessLevel;
     vnode->userAccessLevel = attr->userAccessLevel;
     vnode->historizing = attr->historizing;
     vnode->minimumSamplingInterval = attr->minimumSamplingInterval;
     vnode->valueRank = attr->valueRank;
-    vnode->value.variant.value = attr->value;
-    UA_Variant_init(&attr->value);
+    retval |= UA_Variant_copy(&attr->value, &vnode->value.variant.value);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Node_deleteAnyNodeClass((UA_Node*)vnode);
+        return NULL;
+    }
     return (UA_Node*)vnode;
 }
 
 static UA_Node *
-objectNodeFromAttributes(UA_AddNodesItem *item, UA_ObjectAttributes *attr) {
+objectNodeFromAttributes(const UA_AddNodesItem *item, const UA_ObjectAttributes *attr) {
     UA_ObjectNode *onode = UA_ObjectNode_new();
     if(!onode)
         return NULL;
-    moveStandardAttributes((UA_Node*)onode, item, (UA_NodeAttributes*)attr);
+    UA_StatusCode retval = copyStandardAttributes((UA_Node*)onode, item, (const UA_NodeAttributes*)attr);
     onode->eventNotifier = attr->eventNotifier;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Node_deleteAnyNodeClass((UA_Node*)onode);
+        return NULL;
+    }
     return (UA_Node*)onode;
 }
 
 static UA_Node *
-referenceTypeNodeFromAttributes(UA_AddNodesItem *item, UA_ReferenceTypeAttributes *attr) {
+referenceTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ReferenceTypeAttributes *attr) {
     UA_ReferenceTypeNode *rtnode = UA_ReferenceTypeNode_new();
     if(!rtnode)
         return NULL;
-    moveStandardAttributes((UA_Node*)rtnode, item, (UA_NodeAttributes*)attr);
+    UA_StatusCode retval = copyStandardAttributes((UA_Node*)rtnode, item, (const UA_NodeAttributes*)attr);
     rtnode->isAbstract = attr->isAbstract;
     rtnode->symmetric = attr->symmetric;
-    rtnode->inverseName = attr->inverseName;
-    UA_LocalizedText_init(&attr->inverseName);
+    retval |= UA_LocalizedText_copy(&attr->inverseName, &rtnode->inverseName);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Node_deleteAnyNodeClass((UA_Node*)rtnode);
+        return NULL;
+    }
     return (UA_Node*)rtnode;
 }
 
 static UA_Node *
-objectTypeNodeFromAttributes(UA_AddNodesItem *item, UA_ObjectTypeAttributes *attr) {
+objectTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ObjectTypeAttributes *attr) {
     UA_ObjectTypeNode *otnode = UA_ObjectTypeNode_new();
     if(!otnode)
         return NULL;
-    moveStandardAttributes((UA_Node*)otnode, item, (UA_NodeAttributes*)attr);
+    UA_StatusCode retval = copyStandardAttributes((UA_Node*)otnode, item, (const UA_NodeAttributes*)attr);
     otnode->isAbstract = attr->isAbstract;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Node_deleteAnyNodeClass((UA_Node*)otnode);
+        return NULL;
+    }
     return (UA_Node*)otnode;
 }
 
 static UA_Node *
-variableTypeNodeFromAttributes(UA_AddNodesItem *item, UA_VariableTypeAttributes *attr) {
+variableTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableTypeAttributes *attr) {
     UA_VariableTypeNode *vtnode = UA_VariableTypeNode_new();
     if(!vtnode)
         return NULL;
-    moveStandardAttributes((UA_Node*)vtnode, item, (UA_NodeAttributes*)attr);
-    vtnode->value.variant.value = attr->value;
-    UA_Variant_init(&attr->value);
+    UA_StatusCode retval = copyStandardAttributes((UA_Node*)vtnode, item, (const UA_NodeAttributes*)attr);
+    UA_Variant_copy(&attr->value, &vtnode->value.variant.value);
     // datatype is taken from the value
     vtnode->valueRank = attr->valueRank;
     // array dimensions are taken from the value
     vtnode->isAbstract = attr->isAbstract;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Node_deleteAnyNodeClass((UA_Node*)vtnode);
+        return NULL;
+    }
     return (UA_Node*)vtnode;
 }
 
 static UA_Node *
-viewNodeFromAttributes(UA_AddNodesItem *item, UA_ViewAttributes *attr) {
+viewNodeFromAttributes(const UA_AddNodesItem *item, const UA_ViewAttributes *attr) {
     UA_ViewNode *vnode = UA_ViewNode_new();
     if(!vnode)
         return NULL;
-    moveStandardAttributes((UA_Node*)vnode, item, (UA_NodeAttributes*)attr);
+    UA_StatusCode retval = copyStandardAttributes((UA_Node*)vnode, item, (const UA_NodeAttributes*)attr);
     vnode->containsNoLoops = attr->containsNoLoops;
     vnode->eventNotifier = attr->eventNotifier;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Node_deleteAnyNodeClass((UA_Node*)vnode);
+        return NULL;
+    }
     return (UA_Node*)vnode;
 }
 
 static UA_Node *
-dataTypeNodeFromAttributes(UA_AddNodesItem *item, UA_DataTypeAttributes *attr) {
+dataTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_DataTypeAttributes *attr) {
     UA_DataTypeNode *dtnode = UA_DataTypeNode_new();
     if(!dtnode)
         return NULL;
-    moveStandardAttributes((UA_Node*)dtnode, item, (UA_NodeAttributes*)attr);
+    UA_StatusCode retval = copyStandardAttributes((UA_Node*)dtnode, item, (const UA_NodeAttributes*)attr);
     dtnode->isAbstract = attr->isAbstract;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Node_deleteAnyNodeClass((UA_Node*)dtnode);
+        return NULL;
+    }
     return (UA_Node*)dtnode;
 }
 
-void Service_AddNodes_single(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
+void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
                              UA_AddNodesResult *result) {
     if(item->nodeAttributes.encoding < UA_EXTENSIONOBJECT_DECODED ||
        !item->nodeAttributes.content.decoded.type) {
@@ -590,7 +614,7 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
         return UA_STATUSCODE_BADOUTOFMEMORY;
     }
 
-    moveStandardAttributes((UA_Node*)node, &item, (UA_NodeAttributes*)&attrCopy);
+    copyStandardAttributes((UA_Node*)node, &item, (UA_NodeAttributes*)&attrCopy);
     node->valueSource = UA_VALUESOURCE_DATASOURCE;
     node->value.dataSource = dataSource;
     node->accessLevel = attr.accessLevel;
@@ -650,7 +674,7 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
         return result.statusCode;
     }
     
-    moveStandardAttributes((UA_Node*)node, &item, (UA_NodeAttributes*)&attrCopy);
+    copyStandardAttributes((UA_Node*)node, &item, (UA_NodeAttributes*)&attrCopy);
     node->executable = attrCopy.executable;
     node->userExecutable = attrCopy.executable;
     node->attachedMethod = method;

+ 12 - 10
src/ua_types.c

@@ -351,9 +351,9 @@ processRangeDefinition(const UA_Variant *v, const UA_NumericRange range, size_t
         return UA_STATUSCODE_BADINDEXRANGEINVALID;
     for(size_t i = 0; i < dims_count; i++) {
         if(range.dimensions[i].min > range.dimensions[i].max)
-            return UA_STATUSCODE_BADINDEXRANGEINVALID;
-        if(range.dimensions[i].max > dims[i])
             return UA_STATUSCODE_BADINDEXRANGENODATA;
+        if(range.dimensions[i].max >= dims[i])
+            return UA_STATUSCODE_BADINDEXRANGEINVALID;
         count *= (range.dimensions[i].max - range.dimensions[i].min) + 1;
     }
 
@@ -495,12 +495,11 @@ UA_Variant_setRangeCopy(UA_Variant *v, const void *array, size_t arraySize, cons
     return retval;
 }
 
-UA_StatusCode UA_Variant_setScalar(UA_Variant *v, void * UA_RESTRICT p, const UA_DataType *type) {
+void UA_Variant_setScalar(UA_Variant *v, void * UA_RESTRICT p, const UA_DataType *type) {
     UA_Variant_init(v);
     v->type = type;
     v->arrayLength = 0;
     v->data = p;
-    return UA_STATUSCODE_GOOD;
 }
 
 UA_StatusCode UA_Variant_setScalarCopy(UA_Variant *v, const void *p, const UA_DataType *type) {
@@ -512,16 +511,16 @@ UA_StatusCode UA_Variant_setScalarCopy(UA_Variant *v, const void *p, const UA_Da
 		UA_free(new);
 		return retval;
 	}
-    return UA_Variant_setScalar(v, new, type);
+    UA_Variant_setScalar(v, new, type);
+    return UA_STATUSCODE_GOOD;
 }
 
-UA_StatusCode
+void
 UA_Variant_setArray(UA_Variant *v, void * UA_RESTRICT array, size_t arraySize, const UA_DataType *type) {
     UA_Variant_init(v);
     v->data = array;
     v->arrayLength = arraySize;
     v->type = type;
-    return UA_STATUSCODE_GOOD;
 }
 
 UA_StatusCode
@@ -554,9 +553,10 @@ DataValue_copy(UA_DataValue const *src, UA_DataValue *dst, const UA_DataType *_)
 static void DiagnosticInfo_deleteMembers(UA_DiagnosticInfo *p, const UA_DataType *_) {
     UA_String_deleteMembers(&p->additionalInfo);
     if(p->hasInnerDiagnosticInfo && p->innerDiagnosticInfo) {
-        DiagnosticInfo_deleteMembers(p->innerDiagnosticInfo, _);
+        DiagnosticInfo_deleteMembers(p->innerDiagnosticInfo, NULL);
         UA_free(p->innerDiagnosticInfo);
         p->innerDiagnosticInfo = NULL;
+        p->hasInnerDiagnosticInfo = UA_FALSE;
     }
 }
 
@@ -571,9 +571,11 @@ DiagnosticInfo_copy(UA_DiagnosticInfo const *src, UA_DiagnosticInfo *dst, const
     if(src->hasInnerDiagnosticInfo && src->innerDiagnosticInfo) {
         if((dst->innerDiagnosticInfo = UA_malloc(sizeof(UA_DiagnosticInfo)))) {
             retval |= DiagnosticInfo_copy(src->innerDiagnosticInfo, dst->innerDiagnosticInfo, NULL);
-            dst->hasInnerDiagnosticInfo = src->hasInnerDiagnosticInfo;
-        } else
+            dst->hasInnerDiagnosticInfo = UA_TRUE;
+        } else {
+            dst->hasInnerDiagnosticInfo = UA_FALSE;
             retval |= UA_STATUSCODE_BADOUTOFMEMORY;
+        }
     }
     if(retval != UA_STATUSCODE_GOOD)
         DiagnosticInfo_deleteMembers(dst, NULL);

+ 4 - 6
src/ua_types_encoding_binary.c

@@ -1039,14 +1039,12 @@ DiagnosticInfo_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset
     if(dst->hasInnerDiagnosticInfo) {
         // innerDiagnosticInfo is a pointer to struct, therefore allocate
         dst->innerDiagnosticInfo = UA_calloc(1, sizeof(UA_DiagnosticInfo));
-        if(dst->innerDiagnosticInfo) {
+        if(dst->innerDiagnosticInfo)
             retval |= DiagnosticInfo_decodeBinary(src, offset, dst->innerDiagnosticInfo, NULL);
-            if(retval != UA_STATUSCODE_GOOD) {
-                UA_free(dst->innerDiagnosticInfo);
-                dst->innerDiagnosticInfo = NULL;
-            }
-        } else
+        else {
+            dst->hasInnerDiagnosticInfo = UA_FALSE;
             retval |= UA_STATUSCODE_BADOUTOFMEMORY;
+        }
     }
     if(retval != UA_STATUSCODE_GOOD)
         UA_DiagnosticInfo_deleteMembers(dst);

+ 0 - 3
tests/check_memory.c

@@ -1,5 +1,4 @@
 #define _XOPEN_SOURCE 500
-#include <stdio.h>
 #include <stdlib.h>
 
 #include "ua_types.h"
@@ -53,8 +52,6 @@ START_TEST(encodeShallYieldDecode) {
 	void *obj1 = UA_new(&UA_TYPES[_i]);
     UA_StatusCode retval = UA_ByteString_allocBuffer(&msg1, 65000); // fixed buf size
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
-    printf("%i\n", _i);
-    fflush(stdout);
     retval = UA_encodeBinary(obj1, &UA_TYPES[_i], &msg1, &pos);
     msg1.length = pos;
 	if(retval != UA_STATUSCODE_GOOD) {

+ 45 - 47
tests/check_services_attributes.c

@@ -72,7 +72,7 @@ static UA_Server* makeTestSequence(void) {
     UA_Server_addViewNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWNODE),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
-                          UA_QUALIFIEDNAME_ALLOC(0, "Viewtest"), view_attr, NULL);
+                          UA_QUALIFIEDNAME(0, "Viewtest"), view_attr, NULL);
 
 #ifdef ENABLE_METHODCALLS
 	/* MethodNode */
@@ -92,22 +92,20 @@ static UA_Server* makeTestSequence(void) {
 
 static UA_VariableNode* makeCompareSequence(void) {
 	UA_VariableNode *node = UA_VariableNode_new();
-	UA_Variant *myIntegerVariant = UA_Variant_new();
+
 	UA_Int32 myInteger = 42;
-	UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+	UA_Variant_setScalarCopy(&node->value.variant.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+
 	const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
-	const UA_LocalizedText myIntegerDisplName = UA_LOCALIZEDTEXT("locale", "the answer");
-    const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
-	UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
-	//UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-	node->value.variant.value = *myIntegerVariant;
-	UA_NodeId_copy(&myIntegerNodeId,&node->nodeId);
 	UA_QualifiedName_copy(&myIntegerName,&node->browseName);
+
+	const UA_LocalizedText myIntegerDisplName = UA_LOCALIZEDTEXT("locale", "the answer");
     UA_LocalizedText_copy(&myIntegerDisplName, &node->displayName);
     UA_LocalizedText_copy(&myIntegerDisplName, &node->description);
-    UA_ExpandedNodeId parentId;
-	UA_ExpandedNodeId_init(&parentId);
-	UA_NodeId_copy(&parentNodeId,&parentId.nodeId);
+
+    const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
+	UA_NodeId_copy(&myIntegerNodeId,&node->nodeId);
+
 	return node;
 }
 
@@ -140,7 +138,7 @@ START_TEST(ReadSingleAttributeValueRangeWithoutTimestamp) {
     rReq.nodesToReadSize = 1;
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "myarray");
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
-    rReq.nodesToRead[0].indexRange = UA_STRING_ALLOC("2:3,1:2");
+    rReq.nodesToRead[0].indexRange = UA_STRING_ALLOC("1:2,0:1");
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     ck_assert_int_eq(4, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_INT32], resp.value.type);
@@ -587,11 +585,12 @@ START_TEST(WriteSingleAttributeNodeId) {
     UA_Server *server = makeTestSequence();
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
-    UA_NodeId *id = UA_NodeId_new();
+    UA_NodeId id;
+    UA_NodeId_init(&id);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_NODEID;
     wValue.value.hasValue = UA_TRUE;
-    UA_Variant_setScalar(&wValue.value.value, id, &UA_TYPES[UA_TYPES_NODEID]);
+    UA_Variant_setScalar(&wValue.value.value, &id, &UA_TYPES[UA_TYPES_NODEID]);
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wValue);
     ck_assert_int_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
     UA_Server_delete(server);
@@ -602,10 +601,11 @@ START_TEST(WriteSingleAttributeNodeclass) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
-    UA_NodeClass *class = UA_NodeClass_new();
+    UA_NodeClass class;
+    UA_NodeClass_init(&class);
     wValue.attributeId = UA_ATTRIBUTEID_NODECLASS;
     wValue.value.hasValue = UA_TRUE;
-    UA_Variant_setScalar(&wValue.value.value, class, &UA_TYPES[UA_TYPES_NODECLASS]);
+    UA_Variant_setScalar(&wValue.value.value, &class, &UA_TYPES[UA_TYPES_NODECLASS]);
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wValue);
     ck_assert_int_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
     UA_Server_delete(server);
@@ -616,7 +616,7 @@ START_TEST(WriteSingleAttributeBrowseName) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_QualifiedName testValue = UA_QUALIFIEDNAME(1, "the.answer");
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_BROWSENAME;
     wValue.value.hasValue = UA_TRUE;
@@ -630,7 +630,7 @@ START_TEST(WriteSingleAttributeDisplayName) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_LocalizedText testValue = UA_LOCALIZEDTEXT("en_EN", "the.answer");
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
     wValue.value.hasValue = UA_TRUE;
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_DISPLAYNAME;
@@ -644,7 +644,7 @@ START_TEST(WriteSingleAttributeDescription) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_LocalizedText testValue = UA_LOCALIZEDTEXT("en_EN", "the.answer");
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
     wValue.value.hasValue = UA_TRUE;
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
@@ -660,7 +660,7 @@ START_TEST(WriteSingleAttributeWriteMask) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_Int32 testValue = 0;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_UINT32]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_UINT32]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_WRITEMASK;
@@ -675,7 +675,7 @@ START_TEST(WriteSingleAttributeUserWriteMask) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_Int32 testValue = 0;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_UINT32]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_UINT32]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_USERWRITEMASK;
     wValue.value.hasValue = UA_TRUE;
@@ -689,7 +689,7 @@ START_TEST(WriteSingleAttributeIsAbstract) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_Boolean testValue = UA_TRUE;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_ISABSTRACT;
     wValue.value.hasValue = UA_TRUE;
@@ -703,7 +703,7 @@ START_TEST(WriteSingleAttributeSymmetric) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_Boolean testValue = UA_TRUE;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_SYMMETRIC;
     wValue.value.hasValue = UA_TRUE;
@@ -731,7 +731,7 @@ START_TEST(WriteSingleAttributeContainsNoLoops) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_Boolean testValue = UA_TRUE;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_CONTAINSNOLOOPS;
     wValue.value.hasValue = UA_TRUE;
@@ -745,7 +745,7 @@ START_TEST(WriteSingleAttributeEventNotifier) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_Byte testValue = 0;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BYTE]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BYTE]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_EVENTNOTIFIER;
     wValue.value.hasValue = UA_TRUE;
@@ -758,24 +758,20 @@ START_TEST(WriteSingleAttributeValue) {
     UA_Server *server = makeTestSequence();
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
-    UA_Variant *myIntegerVariant = UA_Variant_new();
     UA_Int32 myInteger = 20;
-    UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+    UA_Variant_setScalar(&wValue.value.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+    wValue.value.hasValue = UA_TRUE;
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_VALUE;
-    wValue.value.hasValue = UA_TRUE;
-    wValue.value.value = *myIntegerVariant;
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wValue);
 
     UA_DataValue resp;
     UA_DataValue_init(&resp);
-    UA_ReadRequest rReq;
-    UA_ReadRequest_init(&rReq);
-    rReq.nodesToRead = UA_ReadValueId_new();
-    rReq.nodesToReadSize = 1;
-    rReq.nodesToRead[0].nodeId = UA_NODEID_STRING(1, "the.answer");
-    rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
-    Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
+    UA_ReadValueId id;
+    UA_ReadValueId_init(&id);
+    id.nodeId = UA_NODEID_STRING(1, "the.answer");
+    id.attributeId = UA_ATTRIBUTEID_VALUE;
+    Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &id, &resp);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert(wValue.value.hasValue);
     ck_assert_int_eq(20, *(UA_Int32*)resp.value.data);
@@ -787,11 +783,12 @@ START_TEST(WriteSingleAttributeDataType) {
     UA_Server *server = makeTestSequence();
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
-    UA_NodeId *typeId = UA_NodeId_new();
+    UA_NodeId typeId;
+    UA_NodeId_init(&typeId);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_DATATYPE;
     wValue.value.hasValue = UA_TRUE;
-    UA_Variant_setScalar(&wValue.value.value, typeId, &UA_TYPES[UA_TYPES_NODEID]);
+    UA_Variant_setScalar(&wValue.value.value, &typeId, &UA_TYPES[UA_TYPES_NODEID]);
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wValue);
     ck_assert_int_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
     UA_Server_delete(server);
@@ -802,7 +799,7 @@ START_TEST(WriteSingleAttributeValueRank) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_Int32 testValue = -1;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_INT32]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_INT32]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_VALUERANK;
     wValue.value.hasValue = UA_TRUE;
@@ -817,7 +814,7 @@ START_TEST(WriteSingleAttributeArrayDimensions) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_Int32 testValue[] = {-1,-1,-1};
-    UA_Variant_setArrayCopy(&wValue.value.value, &testValue, 3, &UA_TYPES[UA_TYPES_INT32]);
+    UA_Variant_setArray(&wValue.value.value, &testValue, 3, &UA_TYPES[UA_TYPES_INT32]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS;
     wValue.value.hasValue = UA_TRUE;
@@ -832,7 +829,7 @@ START_TEST(WriteSingleAttributeAccessLevel) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_Byte testValue = 0;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BYTE]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BYTE]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_ACCESSLEVEL;
     wValue.value.hasValue = UA_TRUE;
@@ -846,7 +843,7 @@ START_TEST(WriteSingleAttributeUserAccessLevel) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_Byte testValue = 0;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BYTE]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BYTE]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_USERACCESSLEVEL;
     wValue.value.hasValue = UA_TRUE;
@@ -860,7 +857,7 @@ START_TEST(WriteSingleAttributeMinimumSamplingInterval) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_Double testValue = 0.0;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_DOUBLE]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_DOUBLE]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL;
     wValue.value.hasValue = UA_TRUE;
@@ -874,7 +871,7 @@ START_TEST(WriteSingleAttributeHistorizing) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_Boolean testValue = UA_TRUE;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_HISTORIZING;
     wValue.value.hasValue = UA_TRUE;
@@ -888,7 +885,7 @@ START_TEST(WriteSingleAttributeExecutable) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_Boolean testValue = UA_TRUE;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_EXECUTABLE;
     wValue.value.hasValue = UA_TRUE;
@@ -902,7 +899,7 @@ START_TEST(WriteSingleAttributeUserExecutable) {
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_Boolean testValue = UA_TRUE;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_USEREXECUTABLE;
     wValue.value.hasValue = UA_TRUE;
@@ -923,6 +920,7 @@ START_TEST(numericRange) {
     ck_assert_int_eq(range.dimensions[1].max,3);
     ck_assert_int_eq(range.dimensions[2].min,5);
     ck_assert_int_eq(range.dimensions[2].max,5);
+    UA_free(range.dimensions);
 } END_TEST
 
 static Suite * testSuite_services_attributes(void) {