commit dc2216b5d050bb906c85150905c3612e3e70725e
Author: Benjamin Berg <benjamin@sipsolutions.net>
Date:   Sun Mar 3 22:17:13 2013 +0100

    Allow calls to g_hash_table_remove from destroy notify functions
    
    Sometimes it might happen that it makes senset to remove a key
    from a hash table from a destroy notify function. An example for
    this is GtkIconInfo, which might remove other icon infos from
    a hash table if it is destroyed.
    
    Without this patch a call to g_hash_table_remove from inside a
    destroy notifier could result in an infinite loop. The patch
    prevents any lookup that occurs during g_hash_table_remove_all
    to fail; which also prevents g_hash_table_remove from doing
    anything.
    
    This fixes bug #695082.

diff --git a/glib/ghash.c b/glib/ghash.c
index 492aa20..bffc626 100644
--- a/glib/ghash.c
+++ b/glib/ghash.c
@@ -475,41 +475,50 @@ g_hash_table_remove_all_nodes (GHashTable *hash_table,
       (hash_table->key_destroy_func == NULL &&
        hash_table->value_destroy_func == NULL))
     {
       memset (hash_table->hashes, 0, hash_table->size * sizeof (guint));
       memset (hash_table->keys, 0, hash_table->size * sizeof (gpointer));
       memset (hash_table->values, 0, hash_table->size * sizeof (gpointer));
 
       return;
     }
 
+  /* Erect tombstone for every node that is going to be deleted.
+   * For all other ones, set to unused.
+   * This way we prevent any operations that might happen on other entries
+   * from destroy notifiers. */
   for (i = 0; i < hash_table->size; i++)
     {
-      if (HASH_IS_REAL (hash_table->hashes[i]))
+      if (HASH_IS_TOMBSTONE (hash_table->hashes[i]))
+        hash_table->hashes[i] = UNUSED_HASH_VALUE;
+      else
+        hash_table->hashes[i] = TOMBSTONE_HASH_VALUE;
+    }
+
+  /* Now destroy all values. */
+  for (i = 0; i < hash_table->size; i++)
+    {
+      if (HASH_IS_TOMBSTONE (hash_table->hashes[i]))
         {
           key = hash_table->keys[i];
           value = hash_table->values[i];
 
           hash_table->hashes[i] = UNUSED_HASH_VALUE;
           hash_table->keys[i] = NULL;
           hash_table->values[i] = NULL;
 
           if (hash_table->key_destroy_func != NULL)
             hash_table->key_destroy_func (key);
 
           if (hash_table->value_destroy_func != NULL)
             hash_table->value_destroy_func (value);
         }
-      else if (HASH_IS_TOMBSTONE (hash_table->hashes[i]))
-        {
-          hash_table->hashes[i] = UNUSED_HASH_VALUE;
-        }
     }
 }
 
 /*
  * g_hash_table_resize:
  * @hash_table: our #GHashTable
  *
  * Resizes the hash table to the optimal size based on the number of
  * nodes currently held. If you call this function then a resize will
  * occur, even if one does not need to occur.
