g_array_maybe_expand silently fails
#include <glib.h>
typedef struct _Point Point;
struct _Point {
double x;
double y;
};
int
main (int argc, char *argv[])
{
Point dummy = { 42, 123 };
g_autoptr (GArray) points = g_array_sized_new (FALSE,
FALSE,
sizeof (Point),
2147483640);
for (guint i = 0; i < 2147483640; i++) {
g_array_append_vals (points, &dummy, 1); // SEGV at i = 134217728
}
return 0;
}
g_array_sized_new
elt_size = 16
reserved_size = 2147483640
array->len = 0
array->alloc = 0
array->elt_size = elt_size = 16
g_array_maybe_expand
G_MAXUINT - array->len == G_MAXUINT - 0, G_MAXUINT > 0 ∴ no g_error
array->len + len == 0 + 2147483640, 2147483640 > 0 ∴ continue
g_array_elt_len (array,
array->len + len + array->zero_terminated) ==
g_array_elt_len (array, 0 + 2147483640 + 0) ==
array->elt_size * 2147483640 ==
16 * 2147483640 == 34359738240
34359738240 > G_MAXUINT ∴ want_alloc = 4294967168 (or 42…)
4294967168 > 0 ∴ continue
want_alloc = g_nearest_pow (want_alloc) == g_nearest_pow (4294967168) == 0
want_alloc = MAX (want_alloc, MIN_ARRAY_SIZE) == MAX (0, 16) == 16
array->data = 16 bytes
array->alloc = 16
array (somewhat by blind luck) can store a single element - "fortunately" we recorded the real allocation size so initially things work
Ultimately g_array_maybe_expand
fails for the 2147483649th point when g_nearest_pow again hits zero thus shrinking the buffer to only 16 bytes - now g_array_append_vals
is memcpy'ing to a address based on an array->len
completely disconnected from reality
…that's not supposed to happen right?
Maybe I'm missing something but I'd expect g_array_maybe_expand
to g_error
in this situation (as g_renew/realloc_n do)
I can't figure out what MAX (want_alloc, MIN_ARRAY_SIZE)
is trying to achieve either - seems like a * array->elt_size
has gone missing but git blame claims line has never changed - mystery