A Leaky Example
The following OPC UA client example connects to a server, writes the value attribute of a string variable node, reads the value back from the server and then closes the connection.
- The client and the UA_String payload are allocated on the heap.
- The UA_NodeId id exists on the stack but contains pointers to memory on the heap allocated by UA_NODEID_STRING_ALLOC.
- The UA_Variant myVariant exists on the stack but contains pointers to memory on the heap. UA_Variant_setScalar() attaches the value of payload to the variant. After the call to UA_Client_readValueAttribute, the value is replaced by the read result which is again allocated on the heap.
For developers coming from C++, the C-style API of open62541 can be very confusing at first. The most confusing part is the memory management because there are lots of ways to create memory leaks.
#include <open62541/client_config_default.h>
#include <open62541/client_highlevel.h>
#include <QDebug>
int main()
{
UA_Client *client = UA_Client_new();
UA_ClientConfig *config = UA_Client_getConfig(client);
UA_ClientConfig_setDefault(config);
UA_StatusCode result = UA_Client_connect(client, "opc.tcp://localhost:4840");
qDebug() << "Status code from connect:" << UA_StatusCode_name(result);
UA_NodeId id = UA_NODEID_STRING_ALLOC(2, "Demo.Static.Scalar.String");
UA_Variant myVariant;
UA_Variant_init(&myVariant);
UA_String *payload = UA_String_new();
*payload = UA_STRING_ALLOC("MyTestValue");
UA_Variant_setScalar(&myVariant, payload, &UA_TYPES[UA_TYPES_STRING]);
result = UA_Client_writeValueAttribute(client, id, &myVariant);
qDebug() << "Status code from write:" << UA_StatusCode_name(result);
result = UA_Client_readValueAttribute(client, id, &myVariant);
qDebug() << "Status code from read:" << UA_StatusCode_name(result);
if (myVariant.data && myVariant.data != UA_EMPTY_ARRAY_SENTINEL) {
UA_String *data = static_cast<UA_String *>(myVariant.data);
const QString qStringValue = QString::fromUtf8(reinterpret_cast<char *>(data->data), data->length);
qDebug() << "Value from server:" << qStringValue;
} else {
qDebug() << "Empty value read from server";
}
result = UA_Client_disconnect(client);
qDebug() << "Status code from disconnect:" << UA_StatusCode_name(result);
return result;
}
The Address Sanitizer
The Memory Management API
- UA_String_new() generates a new instance on the heap
- UA_String_delete() frees an instance on the heap and all memory referenced by it.
- UA_String_init() initializes all values to zero. This is important for structs on the stack to make sure there are no random pointer values when clearing the struct.
- UA_String_clear() / UA_String_deleteMembers() deletes all memory allocated on the heap that it referenced by a struct and initializes all values to zero.
There are also generic functions which take the type as additional parameter
- UA_new(&UA_TYPES[UA_TYPES_STRING])
- UA_delete(value, &UA_TYPES[UA_TYPES_STRING])
- UA_clear(value, &UA_TYPES[UA_TYPES_STRING])
And functions for array handling
- UA_Array_new(length, &UA_TYPES[UA_TYPES_STRING])
- UA_Array_delete(value, length, &UA_TYPES[UA_TYPES_STRING])
Cleanup For The Example Code
The first leak indicated by the address sanitizer is the string part of the UA_NodeId id which has been allocated on the heap and must be freed
Status code from connect: Good
Status code from write: Good
Status code from read: Good
Value from server: "MyTestValue"
Status code from disconnect: Good
=================================================================
==19091==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 25 byte(s) in 1 object(s) allocated from:
#0 0x7de0d8afd9c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x7de0d802cefa in UA_String_fromChars ../open62541/src/ua_types.c:125
#2 0x63f35b5fd78b in UA_NODEID_STRING_ALLOC ../include/open62541/types.h:447
#3 0x63f35b5fdecc in main ../main.cpp:18
#4 0x7de0d782a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#5 0x7de0d782a28a in __libc_start_main_impl ../csu/libc-start.c:360
#6 0x63f35b5fd5e4 in _start (../opc_client+0x25e4) (BuildId: 1b68253fabe238958b36c865c935f90d2b3095d8)
Direct leak of 16 byte(s) in 1 object(s) allocated from:
#0 0x7de0d8afd340 in calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7de0d80300db in UA_new ../open62541/src/ua_types.c:1210
#2 0x7de0d8035cd9 in Variant_decodeBinary ../open62541/src/ua_types_encoding_binary.c:1194
#3 0x7de0d8036247 in DataValue_decodeBinary ../open62541/src/ua_types_encoding_binary.c:1278
#4 0x7de0d80338da in Array_decodeBinary ../open62541/src/ua_types_encoding_binary.c:501
#5 0x7de0d803743d in decodeBinaryStructure ../open62541/src/ua_types_encoding_binary.c:1682
#6 0x7de0d8037a37 in UA_decodeBinaryInternal ../open62541/src/ua_types_encoding_binary.c:1833
#7 0x7de0d80a782d in processMSGResponse ../open62541/src/client/ua_client.c:452
#8 0x7de0d80a7d4a in processServiceResponse ../open62541/src/client/ua_client.c:544
#9 0x7de0d80ad8bb in __Client_networkCallback ../open62541/src/client/ua_client_connect.c:1600
#10 0x7de0d820248d in TCP_connectionSocketCallback ../open62541/arch/eventloop_posix_tcp.c:220
#11 0x7de0d8201632 in UA_EventLoopPOSIX_pollFDs ../open62541/arch/eventloop_posix_epoll.c:123
#12 0x7de0d8200787 in UA_EventLoopPOSIX_run ../open62541/arch/eventloop_posix.c:279
#13 0x7de0d80a8087 in __Client_Service ../open62541/src/client/ua_client.c:626
#14 0x7de0d80a81c9 in __UA_Client_Service ../open62541/src/client/ua_client.c:672
#15 0x7de0d80b0fe9 in UA_Client_Service_read ../open62541/include/open62541/client.h:614
#16 0x7de0d80b3649 in __UA_Client_readAttribute ../open62541/src/client/ua_client_highlevel.c:372
#17 0x63f35b5fd9ae in UA_Client_readValueAttribute ../include/open62541/client_highlevel.h:143
#18 0x63f35b5fe19d in main ../main.cpp:31
#19 0x7de0d782a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#20 0x7de0d782a28a in __libc_start_main_impl ../csu/libc-start.c:360
#21 0x63f35b5fd5e4 in _start (../opc_client+0x25e4) (BuildId: 1b68253fabe238958b36c865c935f90d2b3095d8)
Direct leak of 16 byte(s) in 1 object(s) allocated from:
#0 0x7de0d8afd340 in calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7de0d80300db in UA_new ../open62541/src/ua_types.c:1210
#2 0x63f35b5fd7b0 in UA_String_new ../include/open62541/types_generated_handling.h:423
#3 0x63f35b5fdefd in main ../main.cpp:23
#4 0x7de0d782a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#5 0x7de0d782a28a in __libc_start_main_impl ../csu/libc-start.c:360
#6 0x63f35b5fd5e4 in _start (../opc_client+0x25e4) (BuildId: 1b68253fabe238958b36c865c935f90d2b3095d8)
Indirect leak of 131072 byte(s) in 1 object(s) allocated from:
#0 0x7de0d8afd9c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x7de0d802d8ae in UA_ByteString_allocBuffer ../open62541/src/ua_types.c:309
#2 0x7de0d8200dff in UA_EventLoopPOSIX_allocateRXBuffer ../open62541/arch/eventloop_posix.c:511
#3 0x7de0d82085ee in UDP_eventSourceStart ../open62541/arch/eventloop_posix_udp.c:1311
#4 0x7de0d82003ed in UA_EventLoopPOSIX_start ../open62541/arch/eventloop_posix.c:149
#5 0x7de0d80a9037 in __UA_Client_startup ../open62541/src/client/ua_client.c:1035
#6 0x7de0d80adbfa in initConnect ../open62541/src/client/ua_client_connect.c:1684
#7 0x7de0d80ae0c1 in connectSync ../open62541/src/client/ua_client_connect.c:1768
#8 0x7de0d80ae25e in connectInternal ../open62541/src/client/ua_client_connect.c:1816
#9 0x7de0d80ae337 in __UA_Client_connect ../open62541/src/client/ua_client_connect.c:1835
#10 0x63f35b5fd8c6 in UA_Client_connect ../include/open62541/client.h:378
#11 0x63f35b5fdd63 in main ../main.cpp:14
#12 0x7de0d782a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#13 0x7de0d782a28a in __libc_start_main_impl ../csu/libc-start.c:360
#14 0x63f35b5fd5e4 in _start (../opc_client+0x25e4) (BuildId: 1b68253fabe238958b36c865c935f90d2b3095d8)
Indirect leak of 131072 byte(s) in 1 object(s) allocated from:
#0 0x7de0d8afd9c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x7de0d802d8ae in UA_ByteString_allocBuffer ../open62541/src/ua_types.c:309
#2 0x7de0d8200dff in UA_EventLoopPOSIX_allocateRXBuffer ../open62541/arch/eventloop_posix.c:511
#3 0x7de0d82048ba in TCP_eventSourceStart ../open62541/arch/eventloop_posix_tcp.c:989
#4 0x7de0d82003ed in UA_EventLoopPOSIX_start ../open62541/arch/eventloop_posix.c:149
#5 0x7de0d80a9037 in __UA_Client_startup ../open62541/src/client/ua_client.c:1035
#6 0x7de0d80adbfa in initConnect ../open62541/src/client/ua_client_connect.c:1684
#7 0x7de0d80ae0c1 in connectSync ../open62541/src/client/ua_client_connect.c:1768
#8 0x7de0d80ae25e in connectInternal ../open62541/src/client/ua_client_connect.c:1816
#9 0x7de0d80ae337 in __UA_Client_connect ../open62541/src/client/ua_client_connect.c:1835
#10 0x63f35b5fd8c6 in UA_Client_connect ../include/open62541/client.h:378
#11 0x63f35b5fdd63 in main ../main.cpp:14
#12 0x7de0d782a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#13 0x7de0d782a28a in __libc_start_main_impl ../csu/libc-start.c:360
#14 0x63f35b5fd5e4 in _start (../opc_client+0x25e4) (BuildId: 1b68253fabe238958b36c865c935f90d2b3095d8)
Indirect leak of 1712 byte(s) in 1 object(s) allocated from:
#0 0x7de0d8afd9c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x7de0d80a6a33 in UA_Client_newWithConfig ../open62541/src/client/ua_client.c:110
#2 0x7de0d81f40e6 in UA_Client_new ../open62541/plugins/ua_config_default.c:1094
#3 0x63f35b5fdd1e in main ../main.cpp:9
#4 0x7de0d782a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#5 0x7de0d782a28a in __libc_start_main_impl ../csu/libc-start.c:360
#6 0x63f35b5fd5e4 in _start (../opc_client+0x25e4) (BuildId: 1b68253fabe238958b36c865c935f90d2b3095d8)
Indirect leak of 320 byte(s) in 1 object(s) allocated from:
#0 0x7de0d8afd340 in calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7de0d8200b6c in UA_EventLoop_new_POSIX ../open62541/arch/eventloop_posix.c:435
#2 0x7de0d81f4182 in UA_ClientConfig_setDefault ../open62541/plugins/ua_config_default.c:1125
#3 0x7de0d81f40c1 in UA_Client_new ../open62541/plugins/ua_config_default.c:1091
#4 0x63f35b5fdd1e in main ../main.cpp:9
#5 0x7de0d782a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#6 0x7de0d782a28a in __libc_start_main_impl ../csu/libc-start.c:360
#7 0x63f35b5fd5e4 in _start (../opc_client+0x25e4) (BuildId: 1b68253fabe238958b36c865c935f90d2b3095d8)
Indirect leak of 176 byte(s) in 1 object(s) allocated from:
#0 0x7de0d8afd340 in calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7de0d8204a8c in UA_ConnectionManager_new_POSIX_TCP ../open62541/arch/eventloop_posix_tcp.c:1053
#2 0x7de0d81f41c4 in UA_ClientConfig_setDefault ../open62541/plugins/ua_config_default.c:1130
#3 0x7de0d81f40c1 in UA_Client_new ../open62541/plugins/ua_config_default.c:1091
#4 0x63f35b5fdd1e in main ../main.cpp:9
#5 0x7de0d782a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#6 0x7de0d782a28a in __libc_start_main_impl ../csu/libc-start.c:360
#7 0x63f35b5fd5e4 in _start (../opc_client+0x25e4) (BuildId: 1b68253fabe238958b36c865c935f90d2b3095d8)
Indirect leak of 176 byte(s) in 1 object(s) allocated from:
#0 0x7de0d8afd340 in calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7de0d82087c0 in UA_ConnectionManager_new_POSIX_UDP ../open62541/arch/eventloop_posix_udp.c:1375
#2 0x7de0d81f421d in UA_ClientConfig_setDefault ../open62541/plugins/ua_config_default.c:1135
#3 0x7de0d81f40c1 in UA_Client_new ../open62541/plugins/ua_config_default.c:1091
#4 0x63f35b5fdd1e in main ../main.cpp:9
#5 0x7de0d782a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#6 0x7de0d782a28a in __libc_start_main_impl ../csu/libc-start.c:360
#7 0x63f35b5fd5e4 in _start (../opc_client+0x25e4) (BuildId: 1b68253fabe238958b36c865c935f90d2b3095d8)
Indirect leak of 88 byte(s) in 1 object(s) allocated from:
#0 0x7de0d8afd9c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x7de0d81feda4 in addCallback ../open62541/arch/common/ua_timer.c:61
#2 0x7de0d81feffa in UA_Timer_addRepeatedCallback ../open62541/arch/common/ua_timer.c:121
#3 0x7de0d820006f in UA_EventLoopPOSIX_addCyclicCallback ../open62541/arch/eventloop_posix.c:42
#4 0x7de0d80a8ff0 in __UA_Client_startup ../open62541/src/client/ua_client.c:1026
#5 0x7de0d80adbfa in initConnect ../open62541/src/client/ua_client_connect.c:1684
#6 0x7de0d80ae0c1 in connectSync ../open62541/src/client/ua_client_connect.c:1768
#7 0x7de0d80ae25e in connectInternal ../open62541/src/client/ua_client_connect.c:1816
#8 0x7de0d80ae337 in __UA_Client_connect ../open62541/src/client/ua_client_connect.c:1835
#9 0x63f35b5fd8c6 in UA_Client_connect ../include/open62541/client.h:378
#10 0x63f35b5fdd63 in main ../main.cpp:14
#11 0x7de0d782a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#12 0x7de0d782a28a in __libc_start_main_impl ../csu/libc-start.c:360
#13 0x63f35b5fd5e4 in _start (../opc_client+0x25e4) (BuildId: 1b68253fabe238958b36c865c935f90d2b3095d8)
Indirect leak of 32 byte(s) in 1 object(s) allocated from:
#0 0x7de0d8afd340 in calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7de0d8033793 in Array_decodeBinary ../open62541/src/ua_types_encoding_binary.c:488
#2 0x7de0d80339f9 in String_decodeBinary ../open62541/src/ua_types_encoding_binary.c:520
#3 0x7de0d8037478 in decodeBinaryStructure ../open62541/src/ua_types_encoding_binary.c:1688
#4 0x7de0d8037a37 in UA_decodeBinaryInternal ../open62541/src/ua_types_encoding_binary.c:1833
#5 0x7de0d80a782d in processMSGResponse ../open62541/src/client/ua_client.c:452
#6 0x7de0d80a7d4a in processServiceResponse ../open62541/src/client/ua_client.c:544
#7 0x7de0d80ad8bb in __Client_networkCallback ../open62541/src/client/ua_client_connect.c:1600
#8 0x7de0d820248d in TCP_connectionSocketCallback ../open62541/arch/eventloop_posix_tcp.c:220
#9 0x7de0d8201632 in UA_EventLoopPOSIX_pollFDs ../open62541/arch/eventloop_posix_epoll.c:123
#10 0x7de0d8200787 in UA_EventLoopPOSIX_run ../open62541/arch/eventloop_posix.c:279
#11 0x7de0d80ae1ac in connectSync ../open62541/src/client/ua_client_connect.c:1795
#12 0x7de0d80ae25e in connectInternal ../open62541/src/client/ua_client_connect.c:1816
#13 0x7de0d80ae337 in __UA_Client_connect ../open62541/src/client/ua_client_connect.c:1835
#14 0x63f35b5fd8c6 in UA_Client_connect ../include/open62541/client.h:378
#15 0x63f35b5fdd63 in main ../main.cpp:14
#16 0x7de0d782a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#17 0x7de0d782a28a in __libc_start_main_impl ../csu/libc-start.c:360
#18 0x63f35b5fd5e4 in _start (../opc_client+0x25e4) (BuildId: 1b68253fabe238958b36c865c935f90d2b3095d8)
Indirect leak of 28 byte(s) in 1 object(s) allocated from:
#0 0x7de0d8afd9c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x7de0d802cefa in UA_String_fromChars ../open62541/src/ua_types.c:125
#2 0x7de0d81f431f in UA_ClientConfig_setDefault ../open62541/plugins/ua_config_default.c:1155
#3 0x7de0d81f40c1 in UA_Client_new ../open62541/plugins/ua_config_default.c:1091
#4 0x63f35b5fdd1e in main ../main.cpp:9
#5 0x7de0d782a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#6 0x7de0d782a28a in __libc_start_main_impl ../csu/libc-start.c:360
#7 0x63f35b5fd5e4 in _start (../opc_client+0x25e4) (BuildId: 1b68253fabe238958b36c865c935f90d2b3095d8)
Indirect leak of 25 byte(s) in 1 object(s) allocated from:
#0 0x7de0d8afd9c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x7de0d802cefa in UA_String_fromChars ../open62541/src/ua_types.c:125
#2 0x63f35b5fd8a7 in UA_Client_connect ../include/open62541/client.h:375
#3 0x63f35b5fdd63 in main ../main.cpp:14
#4 0x7de0d782a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#5 0x7de0d782a28a in __libc_start_main_impl ../csu/libc-start.c:360
#6 0x63f35b5fd5e4 in _start (../opc_client+0x25e4) (BuildId: 1b68253fabe238958b36c865c935f90d2b3095d8)
Indirect leak of 22 byte(s) in 1 object(s) allocated from:
#0 0x7de0d8afd340 in calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7de0d803227d in UA_Array_copy ../open62541/src/ua_types.c:1962
#2 0x7de0d802d13c in String_copy ../open62541/src/ua_types.c:172
#3 0x7de0d80305e2 in UA_copy ../open62541/src/ua_types.c:1373
#4 0x7de0d8204d39 in UA_String_copy ../open62541/build/src_generated/open62541/types_generated_handling.h:428
#5 0x7de0d82087f7 in UA_ConnectionManager_new_POSIX_UDP ../open62541/arch/eventloop_posix_udp.c:1380
#6 0x7de0d81f421d in UA_ClientConfig_setDefault ../open62541/plugins/ua_config_default.c:1135
#7 0x7de0d81f40c1 in UA_Client_new ../open62541/plugins/ua_config_default.c:1091
#8 0x63f35b5fdd1e in main ../main.cpp:9
#9 0x7de0d782a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#10 0x7de0d782a28a in __libc_start_main_impl ../csu/libc-start.c:360
#11 0x63f35b5fd5e4 in _start (../opc_client+0x25e4) (BuildId: 1b68253fabe238958b36c865c935f90d2b3095d8)
Indirect leak of 22 byte(s) in 1 object(s) allocated from:
#0 0x7de0d8afd340 in calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7de0d803227d in UA_Array_copy ../open62541/src/ua_types.c:1962
#2 0x7de0d802d13c in String_copy ../open62541/src/ua_types.c:172
#3 0x7de0d80305e2 in UA_copy ../open62541/src/ua_types.c:1373
#4 0x7de0d820183c in UA_String_copy ../open62541/build/src_generated/open62541/types_generated_handling.h:428
#5 0x7de0d8204ac3 in UA_ConnectionManager_new_POSIX_TCP ../open62541/arch/eventloop_posix_tcp.c:1058
#6 0x7de0d81f41c4 in UA_ClientConfig_setDefault ../open62541/plugins/ua_config_default.c:1130
#7 0x7de0d81f40c1 in UA_Client_new ../open62541/plugins/ua_config_default.c:1091
#8 0x63f35b5fdd1e in main ../main.cpp:9
#9 0x7de0d782a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#10 0x7de0d782a28a in __libc_start_main_impl ../csu/libc-start.c:360
#11 0x63f35b5fd5e4 in _start (../opc_client+0x25e4) (BuildId: 1b68253fabe238958b36c865c935f90d2b3095d8)
Indirect leak of 11 byte(s) in 1 object(s) allocated from:
#0 0x7de0d8afd340 in calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7de0d8033793 in Array_decodeBinary ../open62541/src/ua_types_encoding_binary.c:488
#2 0x7de0d80339f9 in String_decodeBinary ../open62541/src/ua_types_encoding_binary.c:520
#3 0x7de0d8035d51 in Variant_decodeBinary ../open62541/src/ua_types_encoding_binary.c:1196
#4 0x7de0d8036247 in DataValue_decodeBinary ../open62541/src/ua_types_encoding_binary.c:1278
#5 0x7de0d80338da in Array_decodeBinary ../open62541/src/ua_types_encoding_binary.c:501
#6 0x7de0d803743d in decodeBinaryStructure ../open62541/src/ua_types_encoding_binary.c:1682
#7 0x7de0d8037a37 in UA_decodeBinaryInternal ../open62541/src/ua_types_encoding_binary.c:1833
#8 0x7de0d80a782d in processMSGResponse ../open62541/src/client/ua_client.c:452
#9 0x7de0d80a7d4a in processServiceResponse ../open62541/src/client/ua_client.c:544
#10 0x7de0d80ad8bb in __Client_networkCallback ../open62541/src/client/ua_client_connect.c:1600
#11 0x7de0d820248d in TCP_connectionSocketCallback ../open62541/arch/eventloop_posix_tcp.c:220
#12 0x7de0d8201632 in UA_EventLoopPOSIX_pollFDs ../open62541/arch/eventloop_posix_epoll.c:123
#13 0x7de0d8200787 in UA_EventLoopPOSIX_run ../open62541/arch/eventloop_posix.c:279
#14 0x7de0d80a8087 in __Client_Service ../open62541/src/client/ua_client.c:626
#15 0x7de0d80a81c9 in __UA_Client_Service ../open62541/src/client/ua_client.c:672
#16 0x7de0d80b0fe9 in UA_Client_Service_read ../open62541/include/open62541/client.h:614
#17 0x7de0d80b3649 in __UA_Client_readAttribute ../open62541/src/client/ua_client_highlevel.c:372
#18 0x63f35b5fd9ae in UA_Client_readValueAttribute ../include/open62541/client_highlevel.h:143
#19 0x63f35b5fe19d in main ../main.cpp:31
#20 0x7de0d782a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#21 0x7de0d782a28a in __libc_start_main_impl ../csu/libc-start.c:360
#22 0x63f35b5fd5e4 in _start (../opc_client+0x25e4) (BuildId: 1b68253fabe238958b36c865c935f90d2b3095d8)
Indirect leak of 11 byte(s) in 1 object(s) allocated from:
#0 0x7de0d8afd9c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x7de0d802cefa in UA_String_fromChars ../open62541/src/ua_types.c:125
#2 0x63f35b5fdf38 in main ../main.cpp:24
#3 0x7de0d782a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#4 0x7de0d782a28a in __libc_start_main_impl ../csu/libc-start.c:360
#5 0x63f35b5fd5e4 in _start (../opc_client+0x25e4) (BuildId: 1b68253fabe238958b36c865c935f90d2b3095d8)
SUMMARY: AddressSanitizer: 264824 byte(s) leaked in 17 allocation(s).
UA_NodeId_clear(&id);
The second leak is the value read from the server by UA_Client_readValueAttribute(). It is also the responsibility of the user to free values the library has attached to a struct passed as output parameter in a function call like UA_Client_readValueAttribute().
UA_Variant_clear(&myVariant);
The third leak is the UA_String payload which has been allocated on the heap via UA_String_new(). It has been created by the user and must be freed by the user.
UA_String_delete(payload);
The first indirect leak is the UA_Client client that has been created using UA_Client_new(). It must also be freed by the user.
UA_Client_delete(client);
Final Leak-free Example
#include <open62541/client_config_default.h>
#include <open62541/client_highlevel.h>
#include <QDebug>
int main()
{
UA_Client *client = UA_Client_new();
UA_ClientConfig *config = UA_Client_getConfig(client);
UA_ClientConfig_setDefault(config);
UA_StatusCode result = UA_Client_connect(client, "opc.tcp://localhost:4840");
qDebug() << "Status code from connect:" << UA_StatusCode_name(result);
UA_NodeId id = UA_NODEID_STRING_ALLOC(2, "Demo.Static.Scalar.String");
UA_Variant myVariant;
UA_Variant_init(&myVariant);
UA_String *payload = UA_String_new();
*payload = UA_STRING_ALLOC("MyTestValue");
UA_Variant_setScalar(&myVariant, payload, &UA_TYPES[UA_TYPES_STRING]);
result = UA_Client_writeValueAttribute(client, id, &myVariant);
qDebug() << "Status code from write:" << UA_StatusCode_name(result);
result = UA_Client_readValueAttribute(client, id, &myVariant);
qDebug() << "Status code from read:" << UA_StatusCode_name(result);
if (myVariant.data && myVariant.data != UA_EMPTY_ARRAY_SENTINEL) {
UA_String *data = static_cast<UA_String *>(myVariant.data);
const QString qStringValue = QString::fromUtf8(reinterpret_cast<char *>(data->data), data->length);
qDebug() << "Value from server:" << qStringValue;
} else {
qDebug() << "Empty value read from server";
}
result = UA_Client_disconnect(client);
qDebug() << "Status code from disconnect:" << UA_StatusCode_name(result);
UA_NodeId_clear(&id);
UA_Variant_clear(&myVariant);
UA_String_delete(payload);
UA_Client_delete(client);
return result;
}
Conclusion: Memory Management With open62541
- Free everything you have directly allocated on the heap with UA_{type}_new() via UA_{type}_delete()
- Initialize all structs on the stack with UA_{type}_init() before using them
- Clear all structs on the stack via UA_{type}_clear() before discarding or overwriting them
- Always use the address sanitizer, even if you know what you are doing