From a3c7406cce2af55aea4ffdf1ceb8b828f5ef3219 Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Thu, 25 Feb 2010 18:09:23 -0500 Subject: [PATCH] GVariantTypeInfo: fix thread safety bug Issue caught by Michael Meeks. This patch based on his. GVariantTypeInfo was dropping the reference count on the TypeInfo structure before removing it from the hash table. This means that another thread could come along and grab the value from the hash table in the meantime. Solve this by holding the lock on the table before dropping the reference. Also: move the hash table initialisation inside of the lock to remove the standard double-initialisation race plus a more insidious issue caused by the fact that we free the hash table once it becomes empty. --- glib/gvarianttypeinfo.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/glib/gvarianttypeinfo.c b/glib/gvarianttypeinfo.c index ee94cb8f9..00fafe914 100644 --- a/glib/gvarianttypeinfo.c +++ b/glib/gvarianttypeinfo.c @@ -739,13 +739,13 @@ g_variant_type_info_get (const GVariantType *type) GVariantTypeInfo *info; gchar *type_string; - if G_UNLIKELY (g_variant_type_info_table == NULL) - g_variant_type_info_table = g_hash_table_new (g_str_hash, - g_str_equal); - type_string = g_variant_type_dup_string (type); g_static_rec_mutex_lock (&g_variant_type_info_lock); + + if (g_variant_type_info_table == NULL) + g_variant_type_info_table = g_hash_table_new (g_str_hash, + g_str_equal); info = g_hash_table_lookup (g_variant_type_info_table, type_string); if (info == NULL) @@ -833,9 +833,9 @@ g_variant_type_info_unref (GVariantTypeInfo *info) { ContainerInfo *container = (ContainerInfo *) info; + g_static_rec_mutex_lock (&g_variant_type_info_lock); if (g_atomic_int_dec_and_test (&container->ref_count)) { - g_static_rec_mutex_lock (&g_variant_type_info_lock); g_hash_table_remove (g_variant_type_info_table, container->type_string); if (g_hash_table_size (g_variant_type_info_table) == 0) @@ -856,6 +856,8 @@ g_variant_type_info_unref (GVariantTypeInfo *info) else g_assert_not_reached (); } + else + g_static_rec_mutex_unlock (&g_variant_type_info_lock); } }