cirrusio
cirrusio

Reputation: 590

Valgrind indicates a memory leak

So, I have some code and Valgrind seems to indicate that there is a memory leak present but I am not seeing it. The code in question is

void *run_client(void *n)
{

    char recv_buffer[1024];

    // This is random, but right now we will allocate 5120 bytes
    // for the data coming from the instrument.
    const int data_size = 5120;
    int numbytes;

    struct net_info *n_info;
    n_info = (struct net_info *)malloc(sizeof(struct net_info));
    n_info = (struct net_info *)n;

    int clientfd;
    clientfd = init_client(&n_info->cfg);

    while (!*(n_info->flag))
    {
        // Clear the buffer every time...
        memset(recv_buffer, 0, 1024);
        if ((numbytes = recv(clientfd, recv_buffer, data_size - 1, 0)) == -1)
        {
            perror("recv");
            exit(1);
        }
        if (recv_buffer[0] != '{' || recv_buffer[numbytes - 1] != '\n')
            continue;

        // remove last two bytes that are EOL indicators
        numbytes -= 2;
        recv_buffer[numbytes] = 0;

        wclear(n_info->packet_win);
        box(n_info->packet_win, 0, 0);

        mvwprintw(n_info->packet_win, 1, 1, "%s", recv_buffer);
        wrefresh(n_info->packet_win);
    }

    close(clientfd);
    free(n_info);
    return 0;
}

I am not sure if the details are necessary, but they are provided here so that you can understand the context. The function above is called from pthread_create and listens on a specified port for data. The string data is then posted to an ncurses window (the code is preliminary and is currently just used for testing). The function exits when the main loop receives a request to exit and the flag in the while loop is set high.

The message from Valgrind is

==24037== 88 bytes in 1 blocks are definitely lost in loss record 14 of 55
==24037==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==24037==    by 0x401897: run_client (ncurses-cpc.c:60)
==24037==    by 0x52906DA: start_thread (pthread_create.c:463)
==24037==    by 0x57D588E: clone (clone.S:95)

and line 60 refers to n_info = (struct net_info *)malloc(sizeof(struct net_info));. As you can see, before exiting the function requests a free of the memory associated with that struct before exiting. Am I missing something? Why is Valgrind flagging this? (the message is posted after the heap summary message when valgrind is run with the option leak-check=yes.)

Upvotes: 0

Views: 255

Answers (2)

Havenard
Havenard

Reputation: 27924

n_info = (struct net_info *)malloc(sizeof(struct net_info));

You just allocated memory... and the very next line:

n_info = (struct net_info *)n;

You overwrite n_info with n, losing the reference to the memory you just allocated. The free() by the end of the function is actually freeing n, not the memory this malloc() allocated.

Upvotes: 0

Ajay Brahmakshatriya
Ajay Brahmakshatriya

Reputation: 9213

From the comments it appears that you want to pass the input struct to the client thread. The leak appears because you allocate some memory and immediately discard the pointer to it.

No, you cannot just do -

struct net_info *n_info = n;

and free the memory from the main loop, because that would lead to use after free bug.

What you need to do is transfer the ownership of this buffer to the thread. This basically means that from the point the thread starts, the input buffer is owned by the thread and it is the thread's responsibility to free it.

You need to remove the new malloc in the thread and just use the pointer directly. The pointer will be free'd after the thread is done using it.

Also be careful that the main loop (or any other thread) should not be sharing the same buffer. This means that the main loop should malloc a separate buffer for every thread it creates.

Upvotes: 2

Related Questions