Digging up memory "problems" in GLib (new user)

After working on some of the GTK tutorials I thought it would be a good idea to acquaint myself with GLib. So I’m going back over some old Advent of Code problems and trying to use as much of GLib as possible. I’ll probably be coming back here regularly with questions (GLib is huge!).

Anyway, I’m trying out the GArray first. Here’s my initial code, as I’m building incrementally:

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

#include <glib.h>

int main()
{
	GArray* input = g_array_new(FALSE, FALSE, sizeof(int));
	for (int n; scanf("%d", &n) == 1; )
		g_array_append_val(input, n);

	int sum = 0;
	for (guint i = 0; i < input->len; ++i)
		sum += g_array_index(input, int, i);

	printf("Sum = %d\n", sum);

	g_array_unref(input);

	return EXIT_SUCCESS;
}

This compiles, of course, and when I do the following I get a memory warning:

$ seq 1 200 > data.txt
$ valgrind ./a.out < data.txt
...
==886029== HEAP SUMMARY:
==886029==     in use at exit: 18,804 bytes in 9 blocks
==886029==   total heap usage: 19 allocs, 10 frees, 25,996 bytes allocated
==886029== 
==886029== LEAK SUMMARY:
==886029==    definitely lost: 0 bytes in 0 blocks
==886029==    indirectly lost: 0 bytes in 0 blocks
==886029==      possibly lost: 0 bytes in 0 blocks
==886029==    still reachable: 18,804 bytes in 9 blocks
==886029==         suppressed: 0 bytes in 0 blocks
==886029== Rerun with --leak-check=full to see details of leaked memory

I’ve searched through the previous posts and found this similar question. So I get it, GLib is probably not freeing reachable memory at termination since the system will reap on exit anyway. Still I wanted to see how the GArray was expanding it’s array and such so I looked up the source on GitLab.

I cannot find g_array_append_val. The online API documentation doesn’t have a listing for it either. But the code compiles and runs as expected.

So IS it okay that g_array_unref doesn’t free it’s memory exactly? If so, why is it okay? I’ve only really begun testing my code with Valgrind and GDB so I’m open to being told I’ve misunderstood something.

Lastly (or probably should have been firstly), is this the right place to ask for help with GLib as a newbie? Next up I’m looking to find a way to get GIO reading my stream and popping out int's. If I have issues is it fine to come here?

Thanks!

It’s a macro defined in garray.h:

/* Resizable arrays. remove fills any cleared spot and shortens the
 * array, while preserving the order. remove_fast will distort the
 * order by moving the last element to the position of the removed.
 */

#define g_array_append_val(a,v)	  g_array_append_vals (a, &(v), 1)
#define g_array_prepend_val(a,v)  g_array_prepend_vals (a, &(v), 1)
#define g_array_insert_val(a,i,v) g_array_insert_vals (a, i, &(v), 1)
#define g_array_index(a,t,i)      (((t*) (void *) (a)->data) [(i)])

So IS it okay that g_array_unref doesn’t free it’s memory exactly? If so, why is it okay? I’ve only really begun testing my code with Valgrind and GDB so I’m open to being told I’ve misunderstood something.

Of course it’s not OK, but I highly doubt anything is wrong with g_array_unref. You need to run with --leak-check=full to show where the leaks are coming from. It’s probably something much deeper than GArray.

My opinion is that GLib and its dependencies should free all memory that it allocates, except for memory that’s accessed from static variables (which valgrind and lsan know not to complain about). We’re a long way from being able to do that, sadly. Other developers have different (I would say less practical) opinions on the matter.

1 Like

It’s a macro defined in garray.h

Aw, man, I looked there! But I was looking near g_array_append_vals. Still, it was just a little above. Okay, so it just calls append_vals with 1. That makes sense. Now I need to track down this g_realloc from g_array_maybe_expand.

Thank you!

GLib ships a Valgrind suppression file under /usr/share/glib-2.0 that you should use.

Deallocating global state, even when detecting a Valgrind run, is not trivial; it gets even less trivial when it comes to make it work portably, and letting additional libraries and application do the same. Plus, once you move outside of GLib, you start getting dependencies that do not deallocate memory on exit, and do not use GLib either, so they’d have to implement their own deallocation policies.

For all practical intents and purposes, it’s a massive swamp that would need to be cleared, and nobody wants to deal with it.