2

I started to learn about POSIX threads and about freeing memory from function called through pthread_create which has inside a malloc call. So I came to the following program:

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

void *foo( void *vargp );

int main( void )
{
    pthread_t thread_id[5];
    const char *msg = "Hello\n";
    char **ptr = NULL;
    printf("Before Thread\n");

    for( int i = 0 ; i < 5 ; i++ )
    {
        pthread_create(&thread_id[i], NULL, foo, (void*)msg);
    }

    for( int i = 0 ; i < 5 ; i++ )
    {
        pthread_join(thread_id[i], ( void* )&ptr );
        free( ptr );
    }

    printf("After Thread\n");
}

void *foo( void *vargp )
{
    char *ptr = malloc( 256 * sizeof( * ptr ) );
    strcpy( ptr, (char*)vargp );
    printf("The message is: %s \n", ptr );
    pthread_exit( ptr );
}

after I run valgrind:

valgrind --leak-check=full --track-origins=yes --show-leak-kinds=all ./Demo

And I get the following Output, which seems to be OK with the memory and there is no leak reported by valgrind:

==5255== Memcheck, a memory error detector
==5255== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5255== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5255== Command: ./Demo
==5255== 
Before Thread
The message is: Hello

The message is: Hello

The message is: Hello

The message is: Hello

The message is: Hello

After Thread
==5255== 
==5255== HEAP SUMMARY:
==5255==     in use at exit: 0 bytes in 0 blocks
==5255==   total heap usage: 16 allocs, 16 frees, 5,358 bytes allocated
==5255== 
==5255== All heap blocks were freed -- no leaks are possible
==5255== 
==5255== For counts of detected and suppressed errors, rerun with: -v
==5255== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Now here is something which I do not understand, if I remove de \n from here:

const char *msg = "Hello\n";

And I compile and run valgrind again, I get:

==5279== Memcheck, a memory error detector
==5279== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5279== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5279== Command: ./Demo
==5279== 
Before Thread
The message is: Hello 
The message is: Hello 
The message is: Hello 
The message is: Hello 
The message is: Hello 
After Thread
==5279== 
==5279== HEAP SUMMARY:
==5279==     in use at exit: 1,638 bytes in 4 blocks
==5279==   total heap usage: 16 allocs, 12 frees, 5,358 bytes allocated
==5279== 
==5279== 36 bytes in 1 blocks are still reachable in loss record 1 of 4
==5279==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5279==    by 0x401D329: strdup (strdup.c:42)
==5279==    by 0x4018656: _dl_load_cache_lookup (dl-cache.c:315)
==5279==    by 0x4009382: _dl_map_object (dl-load.c:2255)
==5279==    by 0x4014EE3: dl_open_worker (dl-open.c:235)
==5279==    by 0x53C92DE: _dl_catch_exception (dl-error-skeleton.c:196)
==5279==    by 0x40147C9: _dl_open (dl-open.c:605)
==5279==    by 0x53C83AC: do_dlopen (dl-libc.c:96)
==5279==    by 0x53C92DE: _dl_catch_exception (dl-error-skeleton.c:196)
==5279==    by 0x53C936E: _dl_catch_error (dl-error-skeleton.c:215)
==5279==    by 0x53C84D8: dlerror_run (dl-libc.c:46)
==5279==    by 0x53C84D8: __libc_dlopen_mode (dl-libc.c:195)
==5279==    by 0x5055DEA: pthread_cancel_init (unwind-forcedunwind.c:52)
==5279== 
==5279== 36 bytes in 1 blocks are still reachable in loss record 2 of 4
==5279==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5279==    by 0x400C3E7: _dl_new_object (dl-object.c:163)
==5279==    by 0x40069A4: _dl_map_object_from_fd (dl-load.c:943)
==5279==    by 0x4008FFB: _dl_map_object (dl-load.c:2389)
==5279==    by 0x4014EE3: dl_open_worker (dl-open.c:235)
==5279==    by 0x53C92DE: _dl_catch_exception (dl-error-skeleton.c:196)
==5279==    by 0x40147C9: _dl_open (dl-open.c:605)
==5279==    by 0x53C83AC: do_dlopen (dl-libc.c:96)
==5279==    by 0x53C92DE: _dl_catch_exception (dl-error-skeleton.c:196)
==5279==    by 0x53C936E: _dl_catch_error (dl-error-skeleton.c:215)
==5279==    by 0x53C84D8: dlerror_run (dl-libc.c:46)
==5279==    by 0x53C84D8: __libc_dlopen_mode (dl-libc.c:195)
==5279==    by 0x5055DEA: pthread_cancel_init (unwind-forcedunwind.c:52)
==5279== 
==5279== 384 bytes in 1 blocks are still reachable in loss record 3 of 4
==5279==    at 0x4C31B25: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5279==    by 0x4011E85: _dl_check_map_versions (dl-version.c:274)
==5279==    by 0x401524B: dl_open_worker (dl-open.c:284)
==5279==    by 0x53C92DE: _dl_catch_exception (dl-error-skeleton.c:196)
==5279==    by 0x40147C9: _dl_open (dl-open.c:605)
==5279==    by 0x53C83AC: do_dlopen (dl-libc.c:96)
==5279==    by 0x53C92DE: _dl_catch_exception (dl-error-skeleton.c:196)
==5279==    by 0x53C936E: _dl_catch_error (dl-error-skeleton.c:215)
==5279==    by 0x53C84D8: dlerror_run (dl-libc.c:46)
==5279==    by 0x53C84D8: __libc_dlopen_mode (dl-libc.c:195)
==5279==    by 0x5055DEA: pthread_cancel_init (unwind-forcedunwind.c:52)
==5279==    by 0x5055FD3: _Unwind_ForcedUnwind (unwind-forcedunwind.c:126)
==5279==    by 0x5053F0F: __pthread_unwind (unwind.c:121)
==5279== 
==5279== 1,182 bytes in 1 blocks are still reachable in loss record 4 of 4
==5279==    at 0x4C31B25: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5279==    by 0x400C100: _dl_new_object (dl-object.c:73)
==5279==    by 0x40069A4: _dl_map_object_from_fd (dl-load.c:943)
==5279==    by 0x4008FFB: _dl_map_object (dl-load.c:2389)
==5279==    by 0x4014EE3: dl_open_worker (dl-open.c:235)
==5279==    by 0x53C92DE: _dl_catch_exception (dl-error-skeleton.c:196)
==5279==    by 0x40147C9: _dl_open (dl-open.c:605)
==5279==    by 0x53C83AC: do_dlopen (dl-libc.c:96)
==5279==    by 0x53C92DE: _dl_catch_exception (dl-error-skeleton.c:196)
==5279==    by 0x53C936E: _dl_catch_error (dl-error-skeleton.c:215)
==5279==    by 0x53C84D8: dlerror_run (dl-libc.c:46)
==5279==    by 0x53C84D8: __libc_dlopen_mode (dl-libc.c:195)
==5279==    by 0x5055DEA: pthread_cancel_init (unwind-forcedunwind.c:52)
==5279== 
==5279== LEAK SUMMARY:
==5279==    definitely lost: 0 bytes in 0 blocks
==5279==    indirectly lost: 0 bytes in 0 blocks
==5279==      possibly lost: 0 bytes in 0 blocks
==5279==    still reachable: 1,638 bytes in 4 blocks
==5279==         suppressed: 0 bytes in 0 blocks
==5279== 
==5279== For counts of detected and suppressed errors, rerun with: -v
==5279== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

So I have 3 Question:

1) - did I free() the malloc correctly

2) - Why I get that output if I remove \n

3) - Do I have (must) to free() that memory inside foo?

To me looks like my Program (somehow) is UB.

1 Answers1

0

1) yes you have correctly free'd the memory

2) the OS internally sometime does some bizarre things that valgrind does not understand. If you do not want to see these messages then you should suppressing rules (http://valgrind.org/docs/manual/manual-core.html#manual-core.suppress)

3) no, as long as you free the memory before the end of the process, it is not a memory leak

coyotemk
  • 133
  • 9
  • Why does this happen only on array of treads like in my example? [If I use a while loop like here](https://ideone.com/8BER3u) there is never a memory leak. This means that I do something wrong here. –  Oct 29 '18 at 20:32
  • If I move `pthread_joinn` and `free()` inside first loop, there is no report from valgrind anymore. [Is this approach OK](https://ideone.com/aJlhfd)? –  Oct 29 '18 at 20:34
  • Sorry for the late comeback. There is never a memory leak in both cases. If you put the pthread_create and pthread_join in the same loop, you create a thread and wait immediately for its termination. – coyotemk Nov 01 '18 at 13:03
  • Sorry for the late comeback. If you put the pthread_create and pthread_join in the same loop, you create a thread and wait immediately for its termination, so there is no parallelism in your program. In order to understand the error given by valgrind, it requires knowledge (which I do not have) of how the OS handles printf's internally. Maybe it will touch some internal buffer that valgrind is not aware of and gives an error. Not all errors that valgrind detects are "true errors", if they come from libraries that you use (and not your own code), then it is their fault not yours :) – coyotemk Nov 01 '18 at 13:11