basysKom AnwendungsEntwicklung

open62541​: memory management essentials
Essential Summary
The C-style API of open62541 can be confusing, the most confusing part is the memory management because there are lots of ways to create memory leaks. Learn how to avoid these pitfalls.

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 address sanitizer is the developer’s best friend for writing memory leak free code with the open62541 library. It can be activated in gcc/g++ and clang by adding the flag -fsanitize=address and adding -lasan to the linker flags.
Let’s run the code above with address sanitizer to see the memory leaks in our application.

The Memory Management API

Open62541 offers a memory management API for all handwritten and generated types. For every type, there are the following functions (example UA_String)
 
  • 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

By adding these four lines to the code, all memory is cleaned up correctly and the additional indirect leaks disappear.
#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
Picture of Jannis Völker

Jannis Völker

Jannis Völker is a software engineer at basysKom GmbH in Darmstadt. After joining basysKom in 2017, he has been working in connectivity projects for embedded devices, Azure based cloud projects and has made contributions to open62541 and the Qt OPC UA module of which he is the current maintainer. He has a background in embedded Linux, Qt and OPC UA and holds a master's degree in computer science from the University of Applied Sciences in Darmstadt.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Weitere Blogartikel

basysKom Newsletter

We collect only the data you enter in this form (no IP address or information that can be derived from it). The collected data is only used in order to send you our regular newsletters, from which you can unsubscribe at any point using the link at the bottom of each newsletter. We will retain this information until you ask us to delete it permanently. For more information about our privacy policy, read Privacy Policy