mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-08-24 09:58:54 +02:00
garray: Support unallocated zero terminated arrays
The g_array_new_take_zero_terminated function could lead to NULL data pointer if it is called with (NULL, FALSE, x), i.e. with a NULL pointer and no clear request. This in turn means that g_array_steal could behave like g_ptr_array_steal, i.e. it would return NULL instead of a zero terminated array, which does not match its description. Also, g_array_remove_range and g_array_set_size could lead to NULL pointer dereferences with such arrays. Support all these cases and adjust the API description to reflect current behavior. It brings GArray and GPtrArray functionality closer to each other without breaking existing API/ABI for programs.
This commit is contained in:
@@ -198,7 +198,9 @@ g_array_new_take (gpointer data,
|
||||
|
||||
/**
|
||||
* g_array_new_take_zero_terminated: (skip)
|
||||
* @data: (array zero-terminated=1): an array of elements of @element_size
|
||||
* @data: (array zero-terminated=1) (transfer full) (nullable): an array
|
||||
* of elements of @element_size, %NULL terminated,
|
||||
* or %NULL for an empty array
|
||||
* @clear: %TRUE if #GArray elements should be automatically cleared
|
||||
* to 0 when they are allocated
|
||||
* @element_size: the size of each element in bytes
|
||||
@@ -271,8 +273,9 @@ g_array_new_take_zero_terminated (gpointer data,
|
||||
* the underlying array is preserved for use elsewhere and returned
|
||||
* to the caller.
|
||||
*
|
||||
* If the array was created with the @zero_terminate property
|
||||
* set to %TRUE, the returned data is zero terminated too.
|
||||
* Note that if the array was created with the @zero_terminate
|
||||
* property set to %TRUE, this may still return %NULL if the length
|
||||
* of the array was zero and data was not yet allocated.
|
||||
*
|
||||
* If array elements contain dynamically-allocated memory,
|
||||
* the array elements should also be freed by the caller.
|
||||
@@ -770,11 +773,12 @@ g_array_set_size (GArray *farray,
|
||||
}
|
||||
else if (length < array->len)
|
||||
g_array_remove_range (farray, length, array->len - length);
|
||||
|
||||
|
||||
array->len = length;
|
||||
|
||||
g_array_zero_terminate (array);
|
||||
|
||||
|
||||
if (G_LIKELY (array->data != NULL))
|
||||
g_array_zero_terminate (array);
|
||||
|
||||
return farray;
|
||||
}
|
||||
|
||||
@@ -881,6 +885,9 @@ g_array_remove_range (GArray *farray,
|
||||
g_return_val_if_fail (index_ <= G_MAXUINT - length, NULL);
|
||||
g_return_val_if_fail (index_ + length <= array->len, NULL);
|
||||
|
||||
if (length == 0)
|
||||
return farray;
|
||||
|
||||
if (array->clear_func != NULL)
|
||||
{
|
||||
guint i;
|
||||
|
@@ -100,6 +100,20 @@ array_set_size (gconstpointer test_data)
|
||||
g_array_unref (garray);
|
||||
}
|
||||
|
||||
/* Check that unallocated zero terminated arrays can be set to size 0. */
|
||||
static void
|
||||
array_set_size_zero_terminated_null (void)
|
||||
{
|
||||
GArray *garray;
|
||||
|
||||
garray = g_array_new_take_zero_terminated(NULL, FALSE, sizeof (gchar));
|
||||
|
||||
g_array_set_size (garray, 0);
|
||||
g_assert_cmpuint (garray->len, ==, 0);
|
||||
|
||||
g_array_free (garray, TRUE);
|
||||
}
|
||||
|
||||
/* As with array_set_size(), but with a sized array. */
|
||||
static void
|
||||
array_set_size_sized (gconstpointer test_data)
|
||||
@@ -307,6 +321,24 @@ array_new_take_zero_terminated (void)
|
||||
g_clear_pointer (&old_data_copy, g_free);
|
||||
}
|
||||
|
||||
/* Check that a non-existing array becomes a zero-terminated one when requested. */
|
||||
static void
|
||||
array_new_take_zero_terminated_null (void)
|
||||
{
|
||||
GArray *garray;
|
||||
gchar *out_str = NULL;
|
||||
gsize len;
|
||||
|
||||
garray = g_array_new_take_zero_terminated (NULL, FALSE, sizeof (gchar));
|
||||
g_assert_cmpuint (garray->len, ==, 0);
|
||||
|
||||
out_str = g_array_steal (garray, &len);
|
||||
g_assert_cmpstr (out_str, ==, NULL);
|
||||
g_assert_cmpuint (len, ==, 0);
|
||||
|
||||
g_free (out_str);
|
||||
}
|
||||
|
||||
static void
|
||||
array_new_take_overflow (void)
|
||||
{
|
||||
@@ -673,6 +705,21 @@ array_remove_range (gconstpointer test_data)
|
||||
g_array_free (garray, TRUE);
|
||||
}
|
||||
|
||||
/* Check that g_array_remove_range() works with a zero terminated array
|
||||
* without any data. */
|
||||
static void
|
||||
array_remove_range_zero_terminated_null (void)
|
||||
{
|
||||
GArray *garray;
|
||||
|
||||
garray = g_array_new_take_zero_terminated(NULL, FALSE, sizeof (gchar));
|
||||
|
||||
g_array_remove_range (garray, 0, 0);
|
||||
g_assert_cmpuint (garray->len, ==, 0);
|
||||
|
||||
g_array_free (garray, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
array_ref_count (void)
|
||||
{
|
||||
@@ -3194,6 +3241,7 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/array/new/take/empty", array_new_take_empty);
|
||||
g_test_add_func ("/array/new/take/overflow", array_new_take_overflow);
|
||||
g_test_add_func ("/array/new/take-zero-terminated", array_new_take_zero_terminated);
|
||||
g_test_add_func ("/array/new/take-zero-terminated/null", array_new_take_zero_terminated_null);
|
||||
g_test_add_func ("/array/ref-count", array_ref_count);
|
||||
g_test_add_func ("/array/steal", array_steal);
|
||||
g_test_add_func ("/array/clear-func", array_clear_func);
|
||||
@@ -3201,6 +3249,8 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/array/copy-sized", test_array_copy_sized);
|
||||
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);
|
||||
g_test_add_func ("/array/set-size/zero-terminated-null", array_set_size_zero_terminated_null);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (array_configurations); i++)
|
||||
{
|
||||
|
Reference in New Issue
Block a user