Home > Blockchain >  Does dereferencing a GArray unref it?
Does dereferencing a GArray unref it?

Time:06-28

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

void transform_pointer_contents(GArray* const arr) {
    GArray* const tmp = g_array_new(true, true, sizeof(uint8_t));
    const uint8_t example_num = 5;
    g_array_append_val(tmp, example_num);

    *arr = *tmp

    // Why does this cause a double-free error?
    g_array_unref(tmp);
}

int main() {
    GArray* const arr = g_array_new(true, true, sizeof(uint8_t));
    transform_pointer_contents(arr);
    printf("Arr length is %d/n", arr->len);

    g_array_unref(arr);
}

Questions

  • Why does the unref at the end of transform_pointer_contents cause a double-free?
  • I suspect that the dereferencing of tmp also unrefs it somehow, if that is true, how does it work? I think that a similar reference-counted type in C would work by overwriting the dereference operator, but surely C doesn't work that way?
  • Do I have a guarantee that tmp is properly freed without the unref?

CodePudding user response:

  • Why does the unref at the end of transform_pointer_contents cause a double-free?

Presumably, it is not either of the GArray objects themselves that is doubly freed, but rather the dynamic space for the temporary object's data (tmp->data). That would be because

*arr = *tmp

performs a shallow copy. When you then decrement the reference count of the temporary, GLib deallocates that internal storage, which arr->data still points to. When arr later becomes unreferenced, GLib tries to deallocate that data again.

Note that it follows also that the data storage originally allocated for the elements of arr was leaked.

The bottom line is that GLib does not support copying GArrays via structure assignment. Instead, use GLib array functions to manipulate GArrays.

  • I suspect that the dereferencing of tmp also unrefs [arr] somehow, if that is true, how does it work?

unrefing tmp does not unref arr. But given your unsupported manipulation of arr, unrefing tmp has a side effect of deallocting the element storage (then) associated with arr.

I think that a similar reference-counted type in C would work by overwriting the dereference operator, but surely C doesn't work that way?

The dereference operator (*) has nothing directly to do with the observed misbehavior, and absolutely nothing to do with GLib's reference counting. Do not conflate the distinct uses of "reference" in play here. And C does not in any case have operator overloading.

The problem is that you have improperly caused the internal state of one GArray to be aliased to the internal state of another, so that when GLib frees one in response to its reference count dropping to zero, the internal state of the other is corrupted. Not that the aliasing was ever a clean situation in the first place.

  • Do I have a guarantee that tmp is properly freed without the unref?

No, you can pretty safely assume that tmp is not properly freed if its reference count is not reduced to zero. So do continue to unref it before you lose the pointer to it. What you need to change is the structure assignment, as described above. Use GLib functions to manipulate the GArrays. There may be viable shortcuts for people who understand GLib well, but at this point, that's not you.

  • Related