Home > Mobile >  c pthread still reachables
c pthread still reachables

Time:06-14

I'm using pthread in my program. It runs fine but valgrind detects still reachables. Always the same bytes: 1654, 4 blocks. Always the same functions visible in valgrind.

Valgrind log:

==29908== Memcheck, a memory error detector
==29908== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==29908== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==29908== Command: ./a.out
==29908== Parent PID: 23902
==29908== 
==29908== 
==29908== HEAP SUMMARY:
==29908==     in use at exit: 1,654 bytes in 4 blocks
==29908==   total heap usage: 8 allocs, 4 frees, 2,526 bytes allocated
==29908== 
==29908== 36 bytes in 1 blocks are still reachable in loss record 1 of 4
==29908==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==29908==    by 0x401F5CE: strdup (strdup.c:42)
==29908==    by 0x4019A81: _dl_load_cache_lookup (dl-cache.c:338)
==29908==    by 0x400A989: _dl_map_object (dl-load.c:2102)
==29908==    by 0x4015D36: dl_open_worker (dl-open.c:513)
==29908==    by 0x49DF8B7: _dl_catch_exception (dl-error-skeleton.c:208)
==29908==    by 0x40155F9: _dl_open (dl-open.c:837)
==29908==    by 0x49DE860: do_dlopen (dl-libc.c:96)
==29908==    by 0x49DF8B7: _dl_catch_exception (dl-error-skeleton.c:208)
==29908==    by 0x49DF982: _dl_catch_error (dl-error-skeleton.c:227)
==29908==    by 0x49DE994: dlerror_run (dl-libc.c:46)
==29908==    by 0x49DE994: __libc_dlopen_mode (dl-libc.c:195)
==29908==    by 0x486E99A: pthread_cancel_init (unwind-forcedunwind.c:53)
==29908== 
==29908== 36 bytes in 1 blocks are still reachable in loss record 2 of 4
==29908==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==29908==    by 0x400D5A7: _dl_new_object (dl-object.c:196)
==29908==    by 0x4006E96: _dl_map_object_from_fd (dl-load.c:997)
==29908==    by 0x400A61A: _dl_map_object (dl-load.c:2236)
==29908==    by 0x4015D36: dl_open_worker (dl-open.c:513)
==29908==    by 0x49DF8B7: _dl_catch_exception (dl-error-skeleton.c:208)
==29908==    by 0x40155F9: _dl_open (dl-open.c:837)
==29908==    by 0x49DE860: do_dlopen (dl-libc.c:96)
==29908==    by 0x49DF8B7: _dl_catch_exception (dl-error-skeleton.c:208)
==29908==    by 0x49DF982: _dl_catch_error (dl-error-skeleton.c:227)
==29908==    by 0x49DE994: dlerror_run (dl-libc.c:46)
==29908==    by 0x49DE994: __libc_dlopen_mode (dl-libc.c:195)
==29908==    by 0x486E99A: pthread_cancel_init (unwind-forcedunwind.c:53)
==29908== 
==29908== 384 bytes in 1 blocks are still reachable in loss record 3 of 4
==29908==    at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==29908==    by 0x401330A: _dl_check_map_versions (dl-version.c:274)
==29908==    by 0x40160EC: dl_open_worker (dl-open.c:577)
==29908==    by 0x49DF8B7: _dl_catch_exception (dl-error-skeleton.c:208)
==29908==    by 0x40155F9: _dl_open (dl-open.c:837)
==29908==    by 0x49DE860: do_dlopen (dl-libc.c:96)
==29908==    by 0x49DF8B7: _dl_catch_exception (dl-error-skeleton.c:208)
==29908==    by 0x49DF982: _dl_catch_error (dl-error-skeleton.c:227)
==29908==    by 0x49DE994: dlerror_run (dl-libc.c:46)
==29908==    by 0x49DE994: __libc_dlopen_mode (dl-libc.c:195)
==29908==    by 0x486E99A: pthread_cancel_init (unwind-forcedunwind.c:53)
==29908==    by 0x486EBB3: _Unwind_ForcedUnwind (unwind-forcedunwind.c:127)
==29908==    by 0x486CF05: __pthread_unwind (unwind.c:121)
==29908== 
==29908== 1,198 bytes in 1 blocks are still reachable in loss record 4 of 4
==29908==    at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==29908==    by 0x400D273: _dl_new_object (dl-object.c:89)
==29908==    by 0x4006E96: _dl_map_object_from_fd (dl-load.c:997)
==29908==    by 0x400A61A: _dl_map_object (dl-load.c:2236)
==29908==    by 0x4015D36: dl_open_worker (dl-open.c:513)
==29908==    by 0x49DF8B7: _dl_catch_exception (dl-error-skeleton.c:208)
==29908==    by 0x40155F9: _dl_open (dl-open.c:837)
==29908==    by 0x49DE860: do_dlopen (dl-libc.c:96)
==29908==    by 0x49DF8B7: _dl_catch_exception (dl-error-skeleton.c:208)
==29908==    by 0x49DF982: _dl_catch_error (dl-error-skeleton.c:227)
==29908==    by 0x49DE994: dlerror_run (dl-libc.c:46)
==29908==    by 0x49DE994: __libc_dlopen_mode (dl-libc.c:195)
==29908==    by 0x486E99A: pthread_cancel_init (unwind-forcedunwind.c:53)
==29908== 
==29908== LEAK SUMMARY:
==29908==    definitely lost: 0 bytes in 0 blocks
==29908==    indirectly lost: 0 bytes in 0 blocks
==29908==      possibly lost: 0 bytes in 0 blocks
==29908==    still reachable: 1,654 bytes in 4 blocks
==29908==         suppressed: 0 bytes in 0 blocks
==29908== 
==29908== For lists of detected and suppressed errors, rerun with: -s
==29908== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

If I limit the program to 1 thread, I never get any still reachables. If I limit it to something low like 2, I sometimes do, sometimes don't. Anything high (48) means I almost always get still reachables.

I managed to reproduce the problem without much code, as follows. What am I doing wrong? If I am doing nothing wrong and it's just pthread things, why is it making still reachables? And why is it semi-random depending on amount of threads?

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

#define NUMTHREADS  2 //can be anything higher than 1 to cause still reachables

void    *thread(void *arg)
{
    (void)arg;
    pthread_exit(EXIT_SUCCESS);
}

int main(void)
{
    int         i;
    pthread_t   threads[NUMTHREADS];

    i = -1;
    while (  i < NUMTHREADS)
        pthread_create(threads   i, NULL, &thread, NULL);
    i = -1;
    while (  i < NUMTHREADS)
        pthread_join(threads[i], NULL);
    return (0);
}

CodePudding user response:

In your thread function, you are doing:

pthread_exit(EXIT_SUCCESS);

Replace with:

return (void *) 0;

Perfect, thank you. Any downsides to exiting threads this way? Do you also have any idea what in pthread is causing these still reachables or why this solution works? – Modin

The [linux, at least] implementation of pthread_create does not put the argument you give it for the thread function (e.g. in your case thread) as the thread start address given to the clone syscall. It gives the pointer to an internal/hidden "helper" start function that does:

  1. Some initialization of thread local storage, etc (which may need to call malloc).
  2. Invokes the "real" function
  3. TLS cleanup/destructors

If we call pthread_exit, we are bypassing step (3).

To see the details, we'd have to get the glibc source and look in nptl/pthread_create.c to the 10 or so steps that get bypassed by not returning.

Personally, I've always "unwound" my call stack to use the return (void *) and only called pthread_exit as an "abort"


Given the [modified] program:

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

#define NUMTHREADS  8                   // can be anything higher than 1 to cause still reachables

void *
thread(void *arg)
{
#if DOEXIT
    (void) arg;
    pthread_exit(EXIT_SUCCESS);
#else
    return (void *) 0;
#endif
}

int
main(void)
{
    int i;
    pthread_t threads[NUMTHREADS];

    i = -1;
    while (  i < NUMTHREADS)
        pthread_create(threads   i, NULL, &thread, NULL);
    i = -1;
    while (  i < NUMTHREADS)
        pthread_join(threads[i], NULL);
    return (0);
}

Note in the test outputs below, the valgrind command is:

valgrind --leak-check=full --show-leak-kinds=all -s ./fix0

Here is the output compiled with -DDOEXIT=1 (that does pthread_exit):

==1659955== Memcheck, a memory error detector
==1659955== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1659955== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==1659955== Command: ./fix0
==1659955==
==1659955==
==1659955== HEAP SUMMARY:
==1659955==     in use at exit: 1,616 bytes in 4 blocks
==1659955==   total heap usage: 13 allocs, 9 frees, 3,848 bytes allocated
==1659955==
==1659955== 21 bytes in 1 blocks are still reachable in loss record 1 of 4
==1659955==    at 0x483780B: malloc (vg_replace_malloc.c:309)
==1659955==    by 0x401C13D: strdup (strdup.c:42)
==1659955==    by 0x4016D0A: _dl_load_cache_lookup (dl-cache.c:306)
==1659955==    by 0x4009592: _dl_map_object (dl-load.c:2107)
==1659955==    by 0x4013A7D: dl_open_worker (dl-open.c:217)
==1659955==    by 0x49F5D66: _dl_catch_exception (dl-error-skeleton.c:196)
==1659955==    by 0x401363D: _dl_open (dl-open.c:588)
==1659955==    by 0x49F5250: do_dlopen (dl-libc.c:96)
==1659955==    by 0x49F5D66: _dl_catch_exception (dl-error-skeleton.c:196)
==1659955==    by 0x49F5E02: _dl_catch_error (dl-error-skeleton.c:215)
==1659955==    by 0x49F5356: dlerror_run (dl-libc.c:46)
==1659955==    by 0x49F53E9: __libc_dlopen_mode (dl-libc.c:195)
==1659955==
==1659955== 21 bytes in 1 blocks are still reachable in loss record 2 of 4
==1659955==    at 0x483780B: malloc (vg_replace_malloc.c:309)
==1659955==    by 0x400BCEF: _dl_new_object (dl-object.c:163)
==1659955==    by 0x400649F: _dl_map_object_from_fd (dl-load.c:1002)
==1659955==    by 0x4009319: _dl_map_object (dl-load.c:2241)
==1659955==    by 0x4013A7D: dl_open_worker (dl-open.c:217)
==1659955==    by 0x49F5D66: _dl_catch_exception (dl-error-skeleton.c:196)
==1659955==    by 0x401363D: _dl_open (dl-open.c:588)
==1659955==    by 0x49F5250: do_dlopen (dl-libc.c:96)
==1659955==    by 0x49F5D66: _dl_catch_exception (dl-error-skeleton.c:196)
==1659955==    by 0x49F5E02: _dl_catch_error (dl-error-skeleton.c:215)
==1659955==    by 0x49F5356: dlerror_run (dl-libc.c:46)
==1659955==    by 0x49F53E9: __libc_dlopen_mode (dl-libc.c:195)
==1659955==
==1659955== 384 bytes in 1 blocks are still reachable in loss record 3 of 4
==1659955==    at 0x4839B1A: calloc (vg_replace_malloc.c:762)
==1659955==    by 0x401142F: _dl_check_map_versions (dl-version.c:274)
==1659955==    by 0x4013B25: dl_open_worker (dl-open.c:266)
==1659955==    by 0x49F5D66: _dl_catch_exception (dl-error-skeleton.c:196)
==1659955==    by 0x401363D: _dl_open (dl-open.c:588)
==1659955==    by 0x49F5250: do_dlopen (dl-libc.c:96)
==1659955==    by 0x49F5D66: _dl_catch_exception (dl-error-skeleton.c:196)
==1659955==    by 0x49F5E02: _dl_catch_error (dl-error-skeleton.c:215)
==1659955==    by 0x49F5356: dlerror_run (dl-libc.c:46)
==1659955==    by 0x49F53E9: __libc_dlopen_mode (dl-libc.c:195)
==1659955==    by 0x48AE45A: pthread_cancel_init (unwind-forcedunwind.c:53)
==1659955==    by 0x48AE673: _Unwind_ForcedUnwind (unwind-forcedunwind.c:127)
==1659955==
==1659955== 1,190 bytes in 1 blocks are still reachable in loss record 4 of 4
==1659955==    at 0x4839B1A: calloc (vg_replace_malloc.c:762)
==1659955==    by 0x400BA11: _dl_new_object (dl-object.c:73)
==1659955==    by 0x400649F: _dl_map_object_from_fd (dl-load.c:1002)
==1659955==    by 0x4009319: _dl_map_object (dl-load.c:2241)
==1659955==    by 0x4013A7D: dl_open_worker (dl-open.c:217)
==1659955==    by 0x49F5D66: _dl_catch_exception (dl-error-skeleton.c:196)
==1659955==    by 0x401363D: _dl_open (dl-open.c:588)
==1659955==    by 0x49F5250: do_dlopen (dl-libc.c:96)
==1659955==    by 0x49F5D66: _dl_catch_exception (dl-error-skeleton.c:196)
==1659955==    by 0x49F5E02: _dl_catch_error (dl-error-skeleton.c:215)
==1659955==    by 0x49F5356: dlerror_run (dl-libc.c:46)
==1659955==    by 0x49F53E9: __libc_dlopen_mode (dl-libc.c:195)
==1659955==
==1659955== LEAK SUMMARY:
==1659955==    definitely lost: 0 bytes in 0 blocks
==1659955==    indirectly lost: 0 bytes in 0 blocks
==1659955==      possibly lost: 0 bytes in 0 blocks
==1659955==    still reachable: 1,616 bytes in 4 blocks
==1659955==         suppressed: 0 bytes in 0 blocks
==1659955==
==1659955== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Here is the output when compiled with -DDOEXIT=0 (does return (void *) 0;):

==1660133== Memcheck, a memory error detector
==1660133== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1660133== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==1660133== Command: ./fix0
==1660133==
==1660133==
==1660133== HEAP SUMMARY:
==1660133==     in use at exit: 0 bytes in 0 blocks
==1660133==   total heap usage: 8 allocs, 8 frees, 2,176 bytes allocated
==1660133==
==1660133== All heap blocks were freed -- no leaks are possible
==1660133==
==1660133== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
  • Related