[glib/glib-2-30] Fix g_hash_table_iter_replace
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/glib-2-30] Fix g_hash_table_iter_replace
- Date: Mon, 24 Oct 2011 17:40:24 +0000 (UTC)
commit 04423e88f71017e6016b8770acda5c421a6b0cc0
Author: Matthias Clasen <mclasen redhat com>
Date: Mon Oct 24 13:25:15 2011 -0400
Fix g_hash_table_iter_replace
When reusing an existing key 'internally', we must avoid calling
the key_destroy function on the old key.
https://bugzilla.gnome.org/show_bug.cgi?id=662544
glib/ghash.c | 17 ++++++++++++-----
glib/tests/hash.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 59 insertions(+), 5 deletions(-)
---
diff --git a/glib/ghash.c b/glib/ghash.c
index 5cc52f1..02c0d7b 100644
--- a/glib/ghash.c
+++ b/glib/ghash.c
@@ -810,10 +810,16 @@ g_hash_table_iter_remove (GHashTableIter *iter)
* @hash_table: our #GHashTable
* @node_index: pointer to node to insert/replace
* @key_hash: key hash
- * @key: key to replace with
+ * @key: key to replace with, or %NULL
* @value: value to replace with
+ * @keep_new_key: whether to replace the key in the node with @key
+ * @reusing_key: whether @key was taken out of the existing node
*
* Inserts a value at @node_index in the hash table and updates it.
+ *
+ * If @key has been taken out of the existing node (ie it is not
+ * passed in via a g_hash_table_insert/replace) call, then @reusing_key
+ * should be %TRUE.
*/
static void
g_hash_table_insert_node (GHashTable *hash_table,
@@ -821,7 +827,8 @@ g_hash_table_insert_node (GHashTable *hash_table,
guint key_hash,
gpointer key,
gpointer value,
- gboolean keep_new_key)
+ gboolean keep_new_key,
+ gboolean reusing_key)
{
guint old_hash;
gpointer old_key;
@@ -862,7 +869,7 @@ g_hash_table_insert_node (GHashTable *hash_table,
if (HASH_IS_REAL (old_hash))
{
- if (hash_table->key_destroy_func)
+ if (hash_table->key_destroy_func && !reusing_key)
hash_table->key_destroy_func (keep_new_key ? old_key : key);
if (hash_table->value_destroy_func)
hash_table->value_destroy_func (old_value);
@@ -903,7 +910,7 @@ g_hash_table_iter_replace (GHashTableIter *iter,
node_hash = ri->hash_table->hashes[ri->position];
key = ri->hash_table->keys[ri->position];
- g_hash_table_insert_node (ri->hash_table, ri->position, node_hash, key, value, TRUE);
+ g_hash_table_insert_node (ri->hash_table, ri->position, node_hash, key, value, TRUE, TRUE);
#ifndef G_DISABLE_ASSERT
ri->version++;
@@ -1098,7 +1105,7 @@ g_hash_table_insert_internal (GHashTable *hash_table,
node_index = g_hash_table_lookup_node (hash_table, key, &key_hash);
- g_hash_table_insert_node (hash_table, node_index, key_hash, key, value, keep_new_key);
+ g_hash_table_insert_node (hash_table, node_index, key_hash, key, value, keep_new_key, FALSE);
}
/**
diff --git a/glib/tests/hash.c b/glib/tests/hash.c
index 687447c..efc23ef 100644
--- a/glib/tests/hash.c
+++ b/glib/tests/hash.c
@@ -1098,6 +1098,52 @@ test_internal_consistency (void)
g_hash_table_unref (h);
}
+static void
+my_key_free (gpointer v)
+{
+ gchar *s = v;
+ g_assert (s[0] != 'x');
+ s[0] = 'x';
+ g_free (v);
+}
+
+static void
+my_value_free (gpointer v)
+{
+ gchar *s = v;
+ g_assert (s[0] != 'y');
+ s[0] = 'y';
+ g_free (v);
+}
+
+static void
+test_iter_replace (void)
+{
+ GHashTable *h;
+ GHashTableIter iter;
+ gpointer k, v;
+ gchar *s;
+
+ g_test_bug ("662544");
+
+ h = g_hash_table_new_full (g_str_hash, g_str_equal, my_key_free, my_value_free);
+
+ g_hash_table_insert (h, g_strdup ("A"), g_strdup ("a"));
+ g_hash_table_insert (h, g_strdup ("B"), g_strdup ("b"));
+ g_hash_table_insert (h, g_strdup ("C"), g_strdup ("c"));
+
+ g_hash_table_iter_init (&iter, h);
+
+ while (g_hash_table_iter_next (&iter, &k, &v))
+ {
+ s = (gchar*)v;
+ g_assert (g_ascii_islower (s[0]));
+ g_hash_table_iter_replace (&iter, g_strdup (k));
+ }
+
+ g_hash_table_unref (h);
+}
+
int
main (int argc, char *argv[])
{
@@ -1123,6 +1169,7 @@ main (int argc, char *argv[])
g_test_add_func ("/hash/lookup-null-key", test_lookup_null_key);
g_test_add_func ("/hash/destroy-modify", test_destroy_modify);
g_test_add_func ("/hash/consistency", test_internal_consistency);
+ g_test_add_func ("/hash/iter-replace", test_iter_replace);
return g_test_run ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]