garray: Avoid exponential growth in g_array_copy

The g_array_copy function uses elt_capacity as length argument for
g_array_sized_new. With a zero terminated array, this effectively
means that the next allocation is doubled in size.

Avoid this by doing the same as g_ptr_array_copy, i.e. use the length.
This makes sure that elt_capacity is roughly the same (only differs
if the copied array has unallocated data in it).
This commit is contained in:
Tobias Stoeckmann
2025-07-18 18:11:42 +02:00
parent 2bba358f0b
commit d90352a43d
2 changed files with 24 additions and 3 deletions

View File

@@ -1589,8 +1589,8 @@ g_array_copy (GArray *array)
g_return_val_if_fail (rarray != NULL, NULL);
new_rarray =
(GRealArray *) g_array_sized_new (rarray->zero_terminated, rarray->clear,
rarray->elt_size, rarray->elt_capacity);
(GRealArray *) g_array_sized_new (rarray->zero_terminated, rarray->clear,
rarray->elt_size, rarray->len);
new_rarray->len = rarray->len;
if (rarray->len > 0)
memcpy (new_rarray->data, rarray->data, g_array_elt_len (rarray, rarray->len));

View File

@@ -1112,6 +1112,26 @@ test_array_copy_sized (void)
g_array_unref (array1);
}
/* Check that copying does not exponentially grow array size. */
static void
test_array_copy_zero_terminated (void)
{
GArray *array;
array = g_array_new_take_zero_terminated (NULL, FALSE, 1);
for (gint i = 0; i < 32; i++)
{
GArray *next;
next = g_array_copy (array);
g_array_unref (array);
array = next;
}
g_array_unref (array);
}
static void
array_overflow_append_vals (void)
{
@@ -3276,7 +3296,8 @@ main (int argc, char *argv[])
g_test_add_func ("/array/steal", array_steal);
g_test_add_func ("/array/clear-func", array_clear_func);
g_test_add_func ("/array/binary-search", test_array_binary_search);
g_test_add_func ("/array/copy-sized", test_array_copy_sized);
g_test_add_func ("/array/copy/sized", test_array_copy_sized);
g_test_add_func ("/array/copy/zero-terminated", test_array_copy_zero_terminated);
g_test_add_func ("/array/overflow-append-vals", array_overflow_append_vals);
g_test_add_func ("/array/overflow-set-size", array_overflow_set_size);
g_test_add_func ("/array/remove-range/zero-terminated-null", array_remove_range_zero_terminated_null);