[glib] GVariantTypeInfo: fix thread safety bug



commit a3c7406cce2af55aea4ffdf1ceb8b828f5ef3219
Author: Ryan Lortie <desrt desrt ca>
Date:   Thu Feb 25 18:09:23 2010 -0500

    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 files changed, 7 insertions(+), 5 deletions(-)
---
diff --git a/glib/gvarianttypeinfo.c b/glib/gvarianttypeinfo.c
index ee94cb8..00fafe9 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);
     }
 }
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]