Merge branch 'th/gdataset-fix-zero-key' into 'main'

[th/gdataset-fix-zero-key] fix and cleanup related to using a zero GQuark for keys in GData

See merge request GNOME/glib!4628
This commit is contained in:
Philip Withnall
2025-05-20 14:17:46 +00:00
2 changed files with 56 additions and 9 deletions

View File

@@ -301,6 +301,10 @@ datalist_append (GData **data, GQuark key_id, gpointer new_data, GDestroyNotify
gboolean reallocated; gboolean reallocated;
GData *d; GData *d;
#ifdef G_ENABLE_DEBUG
g_assert (key_id != 0);
#endif
d = *data; d = *data;
if (!d) if (!d)
{ {
@@ -613,6 +617,10 @@ g_data_set_internal (GData **datalist,
GDataElt old, *data; GDataElt old, *data;
guint32 idx; guint32 idx;
#ifdef G_ENABLE_DEBUG
g_assert (key_id != 0);
#endif
d = g_datalist_lock_and_get (datalist); d = g_datalist_lock_and_get (datalist);
data = datalist_find (d, key_id, &idx); data = datalist_find (d, key_id, &idx);
@@ -1009,8 +1017,11 @@ g_dataset_id_remove_no_notify (gconstpointer dataset_location,
g_return_val_if_fail (dataset_location != NULL, NULL); g_return_val_if_fail (dataset_location != NULL, NULL);
if (key_id == 0)
return NULL;
G_LOCK (g_dataset_global); G_LOCK (g_dataset_global);
if (key_id && g_dataset_location_ht) if (g_dataset_location_ht)
{ {
GDataset *dataset; GDataset *dataset;
@@ -1082,8 +1093,6 @@ g_datalist_id_remove_no_notify (GData **datalist,
* @user_data. * @user_data.
* *
* Returns: the value returned by @callback. * Returns: the value returned by @callback.
*
* Since: 2.80
*/ */
gpointer gpointer
g_datalist_id_update_atomic (GData **datalist, g_datalist_id_update_atomic (GData **datalist,
@@ -1098,6 +1107,9 @@ g_datalist_id_update_atomic (GData **datalist,
GDestroyNotify new_destroy; GDestroyNotify new_destroy;
guint32 idx; guint32 idx;
g_return_val_if_fail (datalist, NULL);
g_return_val_if_fail (key_id != 0, NULL);
d = g_datalist_lock_and_get (datalist); d = g_datalist_lock_and_get (datalist);
data = datalist_find (d, key_id, &idx); data = datalist_find (d, key_id, &idx);
@@ -1198,9 +1210,12 @@ g_dataset_id_get_data (gconstpointer dataset_location,
gpointer retval = NULL; gpointer retval = NULL;
g_return_val_if_fail (dataset_location != NULL, NULL); g_return_val_if_fail (dataset_location != NULL, NULL);
if (key_id == 0)
return NULL;
G_LOCK (g_dataset_global); G_LOCK (g_dataset_global);
if (key_id && g_dataset_location_ht) if (g_dataset_location_ht)
{ {
GDataset *dataset; GDataset *dataset;
@@ -1414,6 +1429,9 @@ g_datalist_get_data (GData **datalist,
g_return_val_if_fail (datalist != NULL, NULL); g_return_val_if_fail (datalist != NULL, NULL);
if (G_UNLIKELY (!key))
return NULL;
d = g_datalist_lock_and_get (datalist); d = g_datalist_lock_and_get (datalist);
if (!d) if (!d)
@@ -1427,6 +1445,8 @@ g_datalist_get_data (GData **datalist,
for (i = 0; i < d->len; i++) for (i = 0; i < d->len; i++)
{ {
const char *qstr;
data_elt = &d->data[i]; data_elt = &d->data[i];
/* Here we intentionally compare by strings, instead of calling /* Here we intentionally compare by strings, instead of calling
* g_quark_try_string() first. * g_quark_try_string() first.
@@ -1434,7 +1454,8 @@ g_datalist_get_data (GData **datalist,
* See commit 1cceda49b60b ('Make g_datalist_get_data not look up the * See commit 1cceda49b60b ('Make g_datalist_get_data not look up the
* quark'). * quark').
*/ */
if (g_strcmp0 (g_quark_to_string (data_elt->key), key) == 0) qstr = g_quark_to_string (data_elt->key);
if (qstr && strcmp (qstr, key) == 0)
{ {
res = data_elt->data; res = data_elt->data;
goto out; goto out;
@@ -1444,7 +1465,7 @@ g_datalist_get_data (GData **datalist,
} }
key_id = g_quark_try_string (key); key_id = g_quark_try_string (key);
if (key_id == 0 && key) if (key_id == 0)
goto out; goto out;
data_elt = g_hash_table_lookup (index, &key_id); data_elt = g_hash_table_lookup (index, &key_id);

View File

@@ -224,14 +224,29 @@ test_datalist_clear (void)
} }
static void static void
test_datalist_basic (void) test_datalist_basic (gconstpointer test_data)
{ {
const gboolean HAS_MANY = GPOINTER_TO_INT (test_data);
const GQuark BOGUS_QUARK = 1000000000u;
GData *list = NULL; GData *list = NULL;
gpointer data; gpointer data;
gpointer ret; gpointer ret;
guint i;
g_datalist_init (&list); g_datalist_init (&list);
data = "one"; data = "one";
if (HAS_MANY)
{
/* Add many entries. This ensures we cover the code path where GData uses
* a lookup hash table. */
for (i = 0; i < 200; i++)
{
/* pick a bogus GQuark. They work fine here. */
g_datalist_id_set_data (&list, BOGUS_QUARK + 1u + i, data);
}
}
g_datalist_set_data (&list, "one", data); g_datalist_set_data (&list, "one", data);
ret = g_datalist_get_data (&list, "one"); ret = g_datalist_get_data (&list, "one");
g_assert_true (ret == data); g_assert_true (ret == data);
@@ -242,6 +257,16 @@ test_datalist_basic (void)
ret = g_datalist_get_data (&list, NULL); ret = g_datalist_get_data (&list, NULL);
g_assert_null (ret); g_assert_null (ret);
/* It is not enforced that GQuark are valid. They are just numbers and work
* too. */
g_datalist_id_set_data (&list, BOGUS_QUARK, data);
ret = g_datalist_id_get_data (&list, BOGUS_QUARK);
g_assert_true (ret == data);
/* Ensure that we don't find the BOGUS_QUARK when looking up by NULL. */
ret = g_datalist_get_data (&list, NULL);
g_assert_null (ret);
g_datalist_clear (&list); g_datalist_clear (&list);
} }
@@ -531,7 +556,8 @@ main (int argc, char *argv[])
g_test_add_func ("/dataset/full", test_dataset_full); g_test_add_func ("/dataset/full", test_dataset_full);
g_test_add_func ("/dataset/foreach", test_dataset_foreach); g_test_add_func ("/dataset/foreach", test_dataset_foreach);
g_test_add_func ("/dataset/destroy", test_dataset_destroy); g_test_add_func ("/dataset/destroy", test_dataset_destroy);
g_test_add_func ("/datalist/basic", test_datalist_basic); g_test_add_data_func ("/datalist/basic/few", GINT_TO_POINTER (FALSE), test_datalist_basic);
g_test_add_data_func ("/datalist/basic/many", GINT_TO_POINTER (TRUE), test_datalist_basic);
g_test_add_func ("/datalist/id", test_datalist_id); g_test_add_func ("/datalist/id", test_datalist_id);
g_test_add_func ("/datalist/recursive-clear", test_datalist_clear); g_test_add_func ("/datalist/recursive-clear", test_datalist_clear);
g_test_add_func ("/datalist/id-remove-multiple", test_datalist_id_remove_multiple); g_test_add_func ("/datalist/id-remove-multiple", test_datalist_id_remove_multiple);