From e9f756f17ef56feb2863c46fbb1698ec8c862839 Mon Sep 17 00:00:00 2001 From: "13:15:29 Tim Janik" Date: Tue, 10 Jun 2008 11:26:50 +0000 Subject: [PATCH] fixed race condition where references to partially initialized classes 2008-06-10 13:15:29 Tim Janik * gtype.c (g_type_class_ref): fixed race condition where references to partially initialized classes could be handed out. svn path=/trunk/; revision=6982 --- gobject/ChangeLog | 5 +++++ gobject/gtype.c | 47 ++++++++++++++++++++--------------------------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/gobject/ChangeLog b/gobject/ChangeLog index 5c3150b..d92a3aa 100644 --- a/gobject/ChangeLog +++ b/gobject/ChangeLog @@ -1,3 +1,8 @@ +2008-06-10 13:15:29 Tim Janik + + * gtype.c (g_type_class_ref): fixed race condition where references to + partially initialized classes could be handed out. + 2008-05-28 Michael Natterer * Makefile.am: don't define G_DISABLE_SINGLE_INCLUDES, it's in diff --git a/gobject/gtype.c b/gobject/gtype.c index 8c8fc41..143e195 100644 --- a/gobject/gtype.c +++ b/gobject/gtype.c @@ -2363,20 +2363,19 @@ gpointer g_type_class_ref (GType type) { TypeNode *node; - - /* optimize for common code path - */ + GType ptype; + + /* optimize for common code path */ G_WRITE_LOCK (&type_rw_lock); node = lookup_type_node_I (type); if (node && node->is_classed && node->data && - node->data->class.class && node->data->common.ref_count > 0) + node->data->class.class && + node->data->class.init_state == INITIALIZED) { type_data_ref_Wm (node); G_WRITE_UNLOCK (&type_rw_lock); - return node->data->class.class; } - if (!node || !node->is_classed || (node->data && node->data->common.ref_count < 1)) { @@ -2385,33 +2384,27 @@ g_type_class_ref (GType type) type_descriptive_name_I (type)); return NULL; } - type_data_ref_Wm (node); + ptype = NODE_PARENT_TYPE (node); + G_WRITE_UNLOCK (&type_rw_lock); + g_static_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */ + /* here, we either have node->data->class.class == NULL, or + * node->data->class.init_state == INITIALIZED, because any + * concurrently running initialization was guarded by class_init_rec_mutex. + */ if (!node->data->class.class) /* class uninitialized */ { - GType ptype = NODE_PARENT_TYPE (node); - GTypeClass *pclass = NULL; - G_WRITE_UNLOCK (&type_rw_lock); - g_static_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */ - if (ptype) - { - pclass = g_type_class_ref (ptype); - G_WRITE_LOCK (&type_rw_lock); - node = lookup_type_node_I (type); - if (node->data->class.class) - INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node)); - } - else - { - G_WRITE_LOCK (&type_rw_lock); - node = lookup_type_node_I (type); - } - if (!node->data->class.class) /* class could have been initialized meanwhile */ - type_class_init_Wm (node, pclass); + /* acquire reference on parent class */ + GTypeClass *pclass = ptype ? g_type_class_ref (ptype) : NULL; + G_WRITE_LOCK (&type_rw_lock); + if (node->data->class.class) /* class was initialized during parent class initialization? */ + INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node)); + type_class_init_Wm (node, pclass); G_WRITE_UNLOCK (&type_rw_lock); - g_static_rec_mutex_unlock (&class_init_rec_mutex); } + g_static_rec_mutex_unlock (&class_init_rec_mutex); + return node->data->class.class; } -- 2.7.4