G_print() makes valgrind to give to many false results where printf() does not

It is getting more and more frustrating that I need to work with C functions where GLIB ones makes my life harder.

I do use suppression file to drop those false responses from valgrind, but the question still remains, why happens in some cases where in my opinion should not, strange results?

The cases which I am talking about are if I am calling g_print() after return in void functions.
The following program explains the situation:

#include <stdio.h>
#include <glib.h>

struct node
{
    int property;
    char name;
    char type;
    struct node *next;
};

struct node *createList ( const int val );
struct node *addNode    ( const int val );
void freeList           ( struct node *head );

int main ( void )
{
    int n_lists = 5;

    struct node *head = createList ( n_lists );

    ( void ) head;

    freeList ( NULL );
}

struct node *createList  ( const int val )
{
    struct node *node = NULL;
    struct node *current = node;

    for ( int i = val ; i > 0 ; i-- )
    {
        current = addNode (  i );
        if ( current == NULL )
        {
            return NULL;
        }
        current->next  = node;
        node = current;
    }

    return node;
}

struct node *addNode ( const int val )
{
    struct node *tmp = malloc ( sizeof ( struct node ) );
    if ( tmp == NULL )
    {
        return NULL;
    }
    tmp->property = val;
    tmp->next = NULL;
    return tmp;
}

void freeList ( struct node *head )
{
    if ( head == NULL )
    {
        printf ( "Error, NULL detected in freeList\n" );
        return;
    }

    g_print ( "Valgrind, Bad Results\n" );
    ///printf  ( "No bad results\n" );

    struct node *current = head;

    while ( current != NULL )
    {
        struct node *tmp = current->next;
        free ( current );
        current = tmp;
    }
}

Here it is indeed the glib.h header file included because I call the g_print() function inside freeList() function after NULL pointer detection.
Basically, the g_print() function never gets callled, because I call freeList in main with NULL argument, but watch how response valgrid on it:

==10357== Memcheck, a memory error detector
==10357== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10357== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==10357== Command: ./GSList
==10357== 
Error, NULL detected in freeList
==10357== 
==10357== HEAP SUMMARY:
==10357==     in use at exit: 18,692 bytes in 11 blocks
==10357==   total heap usage: 12 allocs, 1 frees, 19,716 bytes allocated
==10357== 
==10357== 4 bytes in 1 blocks are still reachable in loss record 1 of 8
==10357==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==10357==    by 0x4905743: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x4905D63: g_private_get (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x48D72A0: g_slice_alloc (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x48A6181: g_hash_table_new_full (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x48C9602: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x4011B89: call_init.part.0 (dl-init.c:72)
==10357==    by 0x4011C90: call_init (dl-init.c:30)
==10357==    by 0x4011C90: _dl_init (dl-init.c:119)
==10357==    by 0x4001139: ??? (in /lib/x86_64-linux-gnu/ld-2.31.so)
==10357== 
==10357== 32 bytes in 1 blocks are still reachable in loss record 2 of 8
==10357==    at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==10357==    by 0x48BED30: g_malloc0 (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x48A4F8F: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x48A61C0: g_hash_table_new_full (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x48C9602: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x4011B89: call_init.part.0 (dl-init.c:72)
==10357==    by 0x4011C90: call_init (dl-init.c:30)
==10357==    by 0x4011C90: _dl_init (dl-init.c:119)
==10357==    by 0x4001139: ??? (in /lib/x86_64-linux-gnu/ld-2.31.so)
==10357== 
==10357== 64 bytes in 1 blocks are still reachable in loss record 3 of 8
==10357==    at 0x483B723: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==10357==    by 0x483E017: realloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==10357==    by 0x48BED7F: g_realloc (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x48A4F7A: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x48A61C0: g_hash_table_new_full (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x48C9602: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x4011B89: call_init.part.0 (dl-init.c:72)
==10357==    by 0x4011C90: call_init (dl-init.c:30)
==10357==    by 0x4011C90: _dl_init (dl-init.c:119)
==10357==    by 0x4001139: ??? (in /lib/x86_64-linux-gnu/ld-2.31.so)
==10357== 
==10357== 64 bytes in 4 blocks are indirectly lost in loss record 4 of 8
==10357==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==10357==    by 0x10925A: addNode (main.c:49)
==10357==    by 0x10920B: createList (main.c:35)
==10357==    by 0x1091C5: main (main.c:21)
==10357== 
==10357== 80 (16 direct, 64 indirect) bytes in 1 blocks are definitely lost in loss record 5 of 8
==10357==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==10357==    by 0x10925A: addNode (main.c:49)
==10357==    by 0x10920B: createList (main.c:35)
==10357==    by 0x1091C5: main (main.c:21)
==10357== 
==10357== 96 bytes in 1 blocks are still reachable in loss record 6 of 8
==10357==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==10357==    by 0x48BECD8: g_malloc (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x48D72C5: g_slice_alloc (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x48A6181: g_hash_table_new_full (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x48C9602: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x4011B89: call_init.part.0 (dl-init.c:72)
==10357==    by 0x4011C90: call_init (dl-init.c:30)
==10357==    by 0x4011C90: _dl_init (dl-init.c:119)
==10357==    by 0x4001139: ??? (in /lib/x86_64-linux-gnu/ld-2.31.so)
==10357== 
==10357== 2,032 bytes in 1 blocks are still reachable in loss record 7 of 8
==10357==    at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==10357==    by 0x48BED30: g_malloc0 (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x48E29C5: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x48D7512: g_slice_alloc (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x48A6181: g_hash_table_new_full (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x48C9602: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x4011B89: call_init.part.0 (dl-init.c:72)
==10357==    by 0x4011C90: call_init (dl-init.c:30)
==10357==    by 0x4011C90: _dl_init (dl-init.c:119)
==10357==    by 0x4001139: ??? (in /lib/x86_64-linux-gnu/ld-2.31.so)
==10357== 
==10357== 16,384 bytes in 1 blocks are still reachable in loss record 8 of 8
==10357==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==10357==    by 0x48BECD8: g_malloc (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x48C9613: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.3)
==10357==    by 0x4011B89: call_init.part.0 (dl-init.c:72)
==10357==    by 0x4011C90: call_init (dl-init.c:30)
==10357==    by 0x4011C90: _dl_init (dl-init.c:119)
==10357==    by 0x4001139: ??? (in /lib/x86_64-linux-gnu/ld-2.31.so)
==10357== 
==10357== LEAK SUMMARY:
==10357==    definitely lost: 16 bytes in 1 blocks
==10357==    indirectly lost: 64 bytes in 4 blocks
==10357==      possibly lost: 0 bytes in 0 blocks
==10357==    still reachable: 18,612 bytes in 6 blocks
==10357==         suppressed: 0 bytes in 0 blocks
==10357== 
==10357== For lists of detected and suppressed errors, rerun with: -s
==10357== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Now if I comment the g_print() call and call printf() the things are looking much more differently:

==10384== Memcheck, a memory error detector
==10384== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10384== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==10384== Command: ./GSList
==10384== 
Error, NULL detected in freeList
==10384== 
==10384== HEAP SUMMARY:
==10384==     in use at exit: 80 bytes in 5 blocks
==10384==   total heap usage: 6 allocs, 1 frees, 1,104 bytes allocated
==10384== 
==10384== 64 bytes in 4 blocks are indirectly lost in loss record 1 of 2
==10384==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==10384==    by 0x10923A: addNode (main.c:49)
==10384==    by 0x1091EB: createList (main.c:35)
==10384==    by 0x1091A5: main (main.c:21)
==10384== 
==10384== 80 (16 direct, 64 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==10384==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==10384==    by 0x10923A: addNode (main.c:49)
==10384==    by 0x1091EB: createList (main.c:35)
==10384==    by 0x1091A5: main (main.c:21)
==10384== 
==10384== LEAK SUMMARY:
==10384==    definitely lost: 16 bytes in 1 blocks
==10384==    indirectly lost: 64 bytes in 4 blocks
==10384==      possibly lost: 0 bytes in 0 blocks
==10384==    still reachable: 0 bytes in 0 blocks
==10384==         suppressed: 0 bytes in 0 blocks
==10384== 
==10384== For lists of detected and suppressed errors, rerun with: -s
==10384== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Now if this case happens in 20-30 functions then you can imagine how many false results has to print valgrind, and the question is WHY?

I am only interested in this particular cases, where g_print should never be called, but valgrind sees it.
What does g_print() function different from printf() in this case?

Valgrind cmd:

valgrind --leak-check=full --track-origins=yes --show-reachable=yes ./program

Because GLib is a complex library, and performs various one-off allocations; also because g_print() is not just a macro around fprintf(), so it performs its own allocations.

The documentation should make it pretty clear:

Outputs a formatted message via the print handler. The default print handler simply outputs the message to stdout, without appending a trailing new-line character. Typically, format should end with its own new-line character.

g_print() should not be used from within libraries for debugging messages, since it may be redirected by applications to special purpose message windows or even files. Instead, libraries should use g_log() , g_log_structured() , or the convenience macros g_message() , g_warning() and g_error() .

If you are linking against GLib, and you’re using Valgrind, you should use the GLib suppression file; it’s called glib.supp and usually installed under /usr/share/glib-2.0/valgrind/—assuming you’re using the system copy of GLib:

valgrind \
  --leak-check=full \
  --track-origins=yes \
  --show-reachable=yes \
  --suppressions=/usr/share/glib-2.0/valgrind/glib.supp \
  ./program

Various libraries ship their own suppression files.

1 Like

Yes, I do not use g_print at all for my personal codes, but I use it a lot in my YouTube videos.
I am kind of GLIB fan anyway :slight_smile:

I do it all the time from here =>> https://people.gnome.org/~johan/gtk.suppression, but never used from my system, I’ll give it a try.

Anyway I am happy with this Answer.
Thank you.

That suppression file is hopelessly outdated. You should use the one shipped by GTK.

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.