garray: Fix copying an array with reserved elements

Spotted by Mohammed Sadiq. `g_array_copy()` was doing a `memcpy()` of
the data from the old array to the new one, based on the reserved
elements in the old array (`array->alloc`). However, the new array was
allocated based on the *assigned* elements in the old array
(`array->len`).

So if the old array had fewer assigned elements than allocated elements,
`memcpy()` would fall off the end of the newly allocated data block.
This was particularly obvious when the old array had no assigned
elements, as the new array’s data pointer would be `NULL`.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

Fixes: #2049
This commit is contained in:
Philip Withnall 2020-02-27 11:20:26 +00:00
parent 70c5fd53e9
commit d22c762221
2 changed files with 32 additions and 2 deletions

View File

@ -1242,9 +1242,12 @@ g_array_copy (GArray *array)
new_rarray =
(GRealArray *) g_array_sized_new (rarray->zero_terminated, rarray->clear,
rarray->elt_size, rarray->len);
rarray->elt_size, rarray->alloc / rarray->elt_size);
new_rarray->len = rarray->len;
memcpy (new_rarray->data, rarray->data, rarray->alloc);
if (rarray->len > 0)
memcpy (new_rarray->data, rarray->data, rarray->len * rarray->elt_size);
g_array_zero_terminate (new_rarray);
return (GArray *) new_rarray;
}

View File

@ -811,6 +811,32 @@ test_array_binary_search (void)
g_array_free (garray, TRUE);
}
static void
test_array_copy_sized (void)
{
GArray *array1 = NULL, *array2 = NULL, *array3 = NULL;
int val = 5;
g_test_summary ("Test that copying a newly-allocated sized array works.");
array1 = g_array_sized_new (FALSE, FALSE, sizeof (int), 1);
array2 = g_array_copy (array1);
g_assert_cmpuint (array2->len, ==, array1->len);
g_array_append_val (array1, val);
array3 = g_array_copy (array1);
g_assert_cmpuint (array3->len, ==, array1->len);
g_assert_cmpuint (g_array_index (array3, int, 0), ==, g_array_index (array1, int, 0));
g_assert_cmpuint (array3->len, ==, 1);
g_assert_cmpuint (g_array_index (array3, int, 0), ==, val);
g_array_unref (array3);
g_array_unref (array2);
g_array_unref (array1);
}
/* Check g_ptr_array_steal() function */
static void
pointer_array_steal (void)
@ -1955,6 +1981,7 @@ 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);
for (i = 0; i < G_N_ELEMENTS (array_configurations); i++)
{