3

Here is a simpler version of my code:

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

void* handle_client(void* arg);

int main(int argc, char *argv[])
{
    pthread_t pthr_handle;
    pthread_create(&pthr_handle, NULL, &handle_client, NULL);
    pthread_detach(pthr_handle);
    pthread_exit(NULL);
    return 0;
}

void* handle_client(void* arg)
{
    printf("Hello from thread!\n");
    pthread_exit(NULL);
    return NULL;
}

When I use valgrind on this program, it says

possibly lost: 272 bytes in 1 blocks

The thing is, it doesn't say that every time I run it. Sometimes it says there are no leaks. Because of that I believe there are no leaks, and the message has something to do with the thread still running after the main thread exits. Isn't the pthread_exit call supposed to make the main thread wait for the other threads to exit? Is there something I can do to make valgrind stop accusing memory leaks?

  • 1
    Valgrind itself probably can't handle still running threads, so if the main thread exits while the detached thread still isn't finished then it will see memory leaks. If the detached thread finishes before the main thread exits, it will all be fine. – Some programmer dude Jan 04 '23 at 13:32
  • 1
    _"Is there something I can do to make valgrind stop accusing memory leaks?"_ [This may help](https://stackoverflow.com/questions/11624545/how-to-make-main-thread-wait-for-all-child-threads-finish). But keep in mind, memory allocated by a program is returned to OS once `main()` returns. – ryyker Jan 04 '23 at 13:38

1 Answers1

3

Valgrind is unable to handle the cleanup that a detached thread performs when it exits after the main thread.

When you run valgrind, add the --gen-suppressions=yes flag:

[dbush@db-centos7 ~]$ valgrind --leak-check=full --gen-suppressions=yes ./x1
==18866== Memcheck, a memory error detector
==18866== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==18866== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==18866== Command: ./x1
==18866== 
Hello from thread!
==18866== 
==18866== HEAP SUMMARY:
==18866==     in use at exit: 560 bytes in 1 blocks
==18866==   total heap usage: 6 allocs, 5 frees, 2,192 bytes allocated
==18866== 
==18866== 560 bytes in 1 blocks are possibly lost in loss record 1 of 1
==18866==    at 0x4C2C089: calloc (vg_replace_malloc.c:762)
==18866==    by 0x4012784: _dl_allocate_tls (in /usr/lib64/ld-2.17.so)
==18866==    by 0x4E3F87B: pthread_create@@GLIBC_2.2.5 (in /usr/lib64/libpthread-2.17.so)
==18866==    by 0x400742: main (x1.c:12)
==18866== 
==18866== 
==18866== ---- Print suppression ? --- [Return/N/n/Y/y/C/c] ---- y
{
   <insert_a_suppression_name_here>
   Memcheck:Leak
   match-leak-kinds: possible
   fun:calloc
   fun:_dl_allocate_tls
   fun:pthread_create@@GLIBC_2.2.5
   fun:main
}
==18866== LEAK SUMMARY:
==18866==    definitely lost: 0 bytes in 0 blocks
==18866==    indirectly lost: 0 bytes in 0 blocks
==18866==      possibly lost: 560 bytes in 1 blocks
==18866==    still reachable: 0 bytes in 0 blocks
==18866==         suppressed: 0 bytes in 0 blocks
==18866== 
==18866== For lists of detected and suppressed errors, rerun with: -s
==18866== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

In the above output, if you respond "Y" to print suppression, it generates a suppression record. You can add this record to a file (adding a name where it says "<insert_a_suppression_name_here>"), then you can pass this file to valgrind using the --suppressions flag:

[dbush@db-centos7 ~]$ valgrind  --suppressions=sup1 ./x1
==18899== Memcheck, a memory error detector
==18899== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==18899== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==18899== Command: ./x1
==18899== 
Hello from thread!
==18899== 
==18899== HEAP SUMMARY:
==18899==     in use at exit: 560 bytes in 1 blocks
==18899==   total heap usage: 6 allocs, 5 frees, 2,192 bytes allocated
==18899== 
==18899== LEAK SUMMARY:
==18899==    definitely lost: 0 bytes in 0 blocks
==18899==    indirectly lost: 0 bytes in 0 blocks
==18899==      possibly lost: 0 bytes in 0 blocks
==18899==    still reachable: 0 bytes in 0 blocks
==18899==         suppressed: 560 bytes in 1 blocks
==18899== 
==18899== For lists of detected and suppressed errors, rerun with: -s
==18899== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Now it shows as a "suppressed" leak, i.e. one you know about and can safely ignore.

dbush
  • 205,898
  • 23
  • 218
  • 273