3

I have a multi-threaded application which uses joinable threads. In order to create the threads (which are in total nthreads workers+1 additional thread) I use a regular call to pthread_create. However, when I try to debug memory leaks, I get a x bytes in y blocks are possibly lost in loss record z of w error, caused by the pthread_create calls.

Here is the part of the code of the program relevant to the issue :

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

int main(){
   int i=0;
   int nthreads=8;

    pthread_t tid_w[nthreads+1]; 

    if( pthread_create(&tid_w[0], NULL, dispatcher, (void*) (size_t) i)<0){
        perror("Creating dispatcher thread");
        return -1;
    }

    for(i=1; i<nthreads+1; i++){
        if( pthread_create(&tid_w[i], NULL, worker, (void*) (size_t) i)<0){
            perror("Creating worker thread");
            return -1;
        }
    }

    // thread joining

    for(i=0; i<nthreads+1; i++){
        if( pthread_join(tid_w[i], NULL)<0){
             perror("Joining thread");
             return -1;
        }
    }

    return 0;
}

This is the output of valgrind (3.11)

==14418== 
==14418== HEAP SUMMARY:
==14418==     in use at exit: 14,496 bytes in 21 blocks
==14418==   total heap usage: 25 allocs, 4 frees, 15,724 bytes allocated
==14418== 
==14418== 560 bytes in 1 blocks are possibly lost in loss record 12 of 14
==14418==    at 0x4C2DB95: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14418==    by 0x40134C4: allocate_dtv (dl-tls.c:322)
==14418==    by 0x40134C4: _dl_allocate_tls (dl-tls.c:544)
==14418==    by 0x4E400D2: allocate_stack (allocatestack.c:588)
==14418==    by 0x4E400D2: pthread_create@@GLIBC_2.2.5 (pthread_create.c:537)
==14418==    by 0x4018AE: main (chatty.c:132)
==14418== 
==14418== 4,480 bytes in 8 blocks are possibly lost in loss record 13 of 14
==14418==    at 0x4C2DB95: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14418==    by 0x40134C4: allocate_dtv (dl-tls.c:322)
==14418==    by 0x40134C4: _dl_allocate_tls (dl-tls.c:544)
==14418==    by 0x4E400D2: allocate_stack (allocatestack.c:588)
==14418==    by 0x4E400D2: pthread_create@@GLIBC_2.2.5 (pthread_create.c:537)
==14418==    by 0x401909: main (chatty.c:138)
==14418== 
==14418== LEAK SUMMARY:
==14418==    definitely lost: 0 bytes in 0 blocks
==14418==    indirectly lost: 0 bytes in 0 blocks
==14418==      possibly lost: 5,040 bytes in 9 blocks
==14418==    still reachable: 9,456 bytes in 12 blocks
==14418==         suppressed: 0 bytes in 0 blocks
==14418== Reachable blocks (those to which a pointer was found) are not shown.
==14418== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==14418== 
==14418== For counts of detected and suppressed errors, rerun with: -v
==14418== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

Line numbers might not match because I have removed a few socket-related parts from the code.

I also have read a lot about pthread_create causing memory leaks but it seems like the issue presents itself when in use of detached threads, which is not my case. Any idea on how to solve the issue?

BattiestFawn66
  • 67
  • 3
  • 10
  • Do the handler functions `dispatcher` and `worker` ever return?. I ask because `pthreads` terminate automatically when the function returns, _or_ when `pthread_exit()` is called from within the calling thread. – ryyker Aug 21 '17 at 13:35
  • @ryyker they both call `pthread_exit(0)` when they finish operating – BattiestFawn66 Aug 21 '17 at 13:36
  • Not the cause of your problem, but `pthread_exit` should not be called in `main`. It could also be glibc not cleaning up properly on termination, there are some edge cases where this happens and it is acceptable as it is freed on program termination. Create more threads and see if the leak gets larger, if not then it's likely something glibc is allocating for thread management and relying on termination for cleanup. – Geoffrey Aug 21 '17 at 13:38
  • You are not using the exit code from `pthread_join()`. There may be some indication of a problem if you looked at that return status. Also, without seeing the worker functions (or at least a minimal representation) it is difficult to say where the problem is. – ryyker Aug 21 '17 at 13:40
  • @Geoffrey Thank you, I'll edit it in the post to make it as correct as possible.I changed return to pthread_exit because I read somewhere that it might have helped with the issue I'm having, but of course it has nothing to do with it. – BattiestFawn66 Aug 21 '17 at 13:40
  • @ryyker I forgot to re-insert the check with the perror statement in the code I posted, but I have done checks and nothing seems to be wrong. – BattiestFawn66 Aug 21 '17 at 13:42
  • 2
    ...without seeing the worker functions (or at least a minimal representation) it is difficult to say where the problem is. – ryyker Aug 21 '17 at 13:43
  • Agreed, this could also be caused by stack corruption somewhere, looking at the source to `pthread_create.c` I do not think that this has anything to do with pthread internals. – Geoffrey Aug 21 '17 at 13:49
  • If I copy paste the code you have here, provide an empty dispatcher and worker thread function, valgrind gives no output about memory still being reachable.Likely there is something else in your code that cause these issues. In particular are there any return statements or exit() calls ? can you with 100% certainty verify the code hits your `pthread_join` calls, and verify that those `pthread_join()` calls succeeds ? Did any of your thread functions detach themselves ? – nos Aug 21 '17 at 13:50
  • You've got n threads, should you not have n-1 `joins`? It appears you may have as many joins as threads. i.e. `for(i=0; i – ryyker Aug 21 '17 at 13:53
  • @nos - Yes, you are right. I failed to count the main thread. – ryyker Aug 21 '17 at 13:56
  • @Geoffrey: Calling `pthread_exit()` from `main()` if perfectly fine. Sometimes it's even necessary. – alk Aug 21 '17 at 16:27
  • 2
    Same issue, glibc developper's answer in 2007 (https://sourceware.org/bugzilla/show_bug.cgi?id=5171) is mostly "don't annoy me". – Étienne Jul 11 '18 at 06:43

0 Answers0