Home > Software engineering >  Memory leak when using readline in joined or detached thread
Memory leak when using readline in joined or detached thread

Time:04-12

For the past 2 hours or so, I have been trying to figure out why the following code throws a "possibly lost" memory leak:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#include <readline/readline.h>
#include <readline/history.h>

void *my_read(void* arg) {
    char* buf;
    if ((buf = readline(">> ")) != NULL) {
        printf("Test\n");
        if (strlen(buf) > 0) {
            add_history(buf);
        }
        free(buf);
    }
  
    pthread_exit(0);
}

int main(int argc, char** argv) {
    rl_catch_signals = 0;
    pthread_t thread;
    pthread_create(&thread, NULL, my_read, NULL);
    pthread_join(thread, NULL);
    return 0;
}

And I have also tried using detach instead of join, but the result is the same, which is:

==1498903== 272 bytes in 1 blocks are possibly lost in loss record 31 of 78
==1498903==    at 0x4849C0F: calloc (vg_replace_malloc.c:1328)
==1498903==    by 0x4012662: allocate_dtv (in /lib64/ld-linux-x86-64.so.2)
==1498903==    by 0x401309D: _dl_allocate_tls (in /lib64/ld-linux-x86-64.so.2)
==1498903==    by 0x497FAA4: pthread_create@@GLIBC_2.34 (in /lib64/libc.so.6)
==1498903==    by 0x10927B: main (in /home/user/readline)

I have also tried just straight up allocating memory and freeing it in a loop, which shows the same result.

EDIT: Picked the read -> my_read fix from Ajay, but the main issue still remains.

CodePudding user response:

The main problem here is that you have defined a function named read. Readline internally calls the read function to read from stdin. This ends up recursively calling your read function leading to a stackoverflow and crashing your program. The crashed program doesn't free memory for the pthread_t state which should be done when you call pthread_join. This is the main reason valgrind complains.

A simple fix is to read --> my_read.

With the proposed fix the output of valgrind --leak-check=full on my end is -

==27167== Memcheck, a memory error detector
==27167== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==27167== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==27167== Command: ./test
==27167==
>> hello
Test
==27167==
==27167== HEAP SUMMARY:
==27167==     in use at exit: 134,297 bytes in 195 blocks
==27167==   total heap usage: 316 allocs, 121 frees, 155,633 bytes allocated
==27167==
==27167== LEAK SUMMARY:
==27167==    definitely lost: 0 bytes in 0 blocks
==27167==    indirectly lost: 0 bytes in 0 blocks
==27167==      possibly lost: 0 bytes in 0 blocks
==27167==    still reachable: 134,297 bytes in 195 blocks
==27167==         suppressed: 0 bytes in 0 blocks
==27167== Reachable blocks (those to which a pointer was found) are not shown.
==27167== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==27167==
==27167== For counts of detected and suppressed errors, rerun with: -v
==27167== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
  •  Tags:  
  • c
  • Related