Преглед изворни кода

Fixed SEGFAULT when attempting to read a datasource's datatype that did not return a value (but set the hasValue field).

ichrispa пре 9 година
родитељ
комит
4a3a1c7966

+ 3 - 1
src/server/ua_services_attribute.c

@@ -162,10 +162,12 @@ static UA_StatusCode getVariableNodeDataType(const UA_VariableNode *vn, UA_DataV
         /* Read from the datasource to see the data type */
         UA_DataValue val;
         UA_DataValue_init(&val);
+        val.hasValue = UA_FALSE; // always assume we are not given a value by userspace
         retval = vn->value.dataSource.read(vn->value.dataSource.handle, vn->nodeId, UA_FALSE, NULL, &val);
         if(retval != UA_STATUSCODE_GOOD)
             return retval;
-        retval = UA_Variant_setScalarCopy(&v->value, &val.value.type->typeId, &UA_TYPES[UA_TYPES_NODEID]);
+        if (val.hasValue && val.value.type != NULL)
+          retval = UA_Variant_setScalarCopy(&v->value, &val.value.type->typeId, &UA_TYPES[UA_TYPES_NODEID]);
         UA_DataValue_deleteMembers(&val);
     }
     return retval;

+ 1 - 1
src/server/ua_services_nodemanagement.c

@@ -290,7 +290,7 @@ instantiateObjectNode(UA_Server *server, UA_Session *session,
 
 static UA_StatusCode
 instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
-                        const UA_NodeId *typeId, UA_InstantiationCallback *instantiationCallback) {
+    const UA_NodeId *typeId, UA_InstantiationCallback *instantiationCallback) {
     const UA_ObjectTypeNode *type = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
     if(!type)
         return UA_STATUSCODE_BADNODEIDINVALID;

+ 2 - 0
src/ua_types.c

@@ -526,6 +526,8 @@ UA_StatusCode UA_Variant_setScalarCopy(UA_Variant *v, const void *p, const UA_Da
     void *new = UA_malloc(type->memSize);
     if(!new)
         return UA_STATUSCODE_BADOUTOFMEMORY;
+    if(!v)
+        return UA_STATUSCODE_BADINTERNALERROR;
     UA_StatusCode retval = UA_copy(p, new, type);
 	if(retval != UA_STATUSCODE_GOOD) {
 		UA_free(new);

+ 38 - 2
tests/check_services_attributes.c

@@ -17,6 +17,15 @@
 #include <urcu.h>
 #endif
 
+UA_StatusCode readCPUTemperature_broken(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
+                                        const UA_NumericRange *range, UA_DataValue *dataValue);
+UA_StatusCode readCPUTemperature_broken(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
+                                        const UA_NumericRange *range, UA_DataValue *dataValue) 
+{
+  dataValue->hasValue = UA_TRUE;
+  return UA_STATUSCODE_GOOD;
+}
+
 static UA_Server* makeTestSequence(void) {
     UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
 
@@ -47,8 +56,17 @@ static UA_Server* makeTestSequence(void) {
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
 					UA_QUALIFIEDNAME(1, "cpu temperature"),
                                         UA_NODEID_NULL, vattr, temperatureDataSource, NULL);
-
     
+    /* DataSource Variable returning no value */
+    UA_DataSource temperatureDataSource1 = (UA_DataSource) {
+                                            .handle = NULL, .read = readCPUTemperature_broken, .write = NULL};
+    vattr.description = UA_LOCALIZEDTEXT("en_US","temperature1");
+    vattr.displayName = UA_LOCALIZEDTEXT("en_US","temperature1");
+    UA_Server_addDataSourceVariableNode(server, UA_NODEID_STRING(1, "cpu.temperature1"),
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                                        UA_QUALIFIEDNAME(1, "cpu temperature bogus"),
+                                        UA_NODEID_NULL, vattr, temperatureDataSource1, NULL);
     /* VariableNode with array */
     UA_VariableAttributes_init(&vattr);
     UA_Int32 myIntegerArray[9] = {1,2,3,4,5,6,7,8,9};
@@ -592,6 +610,23 @@ START_TEST(ReadSingleAttributeUserExecutableWithoutTimestamp) {
 #endif
 } END_TEST
 
+START_TEST(ReadSingleDataSourceAttributeDataTypeWithoutTimestampFromBrokenSource) {
+    UA_Server *server = makeTestSequence();
+    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_ALLOC(1, "cpu.temperature1");
+    rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_DATATYPE;
+    Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
+    ck_assert_int_eq(UA_STATUSCODE_GOOD, resp.status);
+    UA_Server_delete(server);
+    UA_ReadRequest_deleteMembers(&rReq);
+    UA_DataValue_deleteMembers(&resp);
+} END_TEST
+
 START_TEST(ReadSingleDataSourceAttributeValueWithoutTimestamp) {
     UA_Server *server = makeTestSequence();
     UA_DataValue resp;
@@ -1028,7 +1063,8 @@ static Suite * testSuite_services_attributes(void) {
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeHistorizingWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeExecutableWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeUserExecutableWithoutTimestamp);
-	tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeValueWithoutTimestamp);
+        tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeDataTypeWithoutTimestampFromBrokenSource);
+        tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeValueWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeDataTypeWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeArrayDimensionsWithoutTimestamp);