From aede77464259e6d50e724113c16f301367201a72 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 21 Feb 2013 16:10:36 +0100 Subject: [PATCH] signals: Ensure we ref handler in emission fast path We need to keep a reference to the handler in the fast path, just like in the slow path, otherwise if another thread disconnects the handler we may destroy the closure while we're using it without the lock held. We also move the freeing of the instance to after the emission is totally done as the handler_unref_R (and the tracepoint) reference it. https://bugzilla.gnome.org/show_bug.cgi?id=694253 --- gobject/gsignal.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/gobject/gsignal.c b/gobject/gsignal.c index 061f16f83..e2a84393e 100644 --- a/gobject/gsignal.c +++ b/gobject/gsignal.c @@ -3127,6 +3127,7 @@ g_signal_emit_valist (gpointer instance, ) { HandlerList* hlist = handler_list_lookup (node->signal_id, instance); + Handler *fastpath_handler = NULL; Handler *l; GClosure *closure = NULL; gboolean fastpath = TRUE; @@ -3159,6 +3160,7 @@ g_signal_emit_valist (gpointer instance, } else { + fastpath_handler = l; closure = l->closure; if (l->after) run_type = G_SIGNAL_RUN_LAST; @@ -3207,6 +3209,9 @@ g_signal_emit_valist (gpointer instance, emission.chain_type = instance_type; emission_push (&g_recursive_emissions, &emission); + if (fastpath_handler) + handler_ref (fastpath_handler); + SIGNAL_UNLOCK (); TRACE(GOBJECT_SIGNAL_EMIT(signal_id, detail, instance, instance_type)); @@ -3227,7 +3232,6 @@ g_signal_emit_valist (gpointer instance, node->n_params, node->param_types); accumulate (&emission.ihint, &emission_return, &accu, accumulator); - g_object_unref (instance); } SIGNAL_LOCK (); @@ -3235,6 +3239,9 @@ g_signal_emit_valist (gpointer instance, emission.chain_type = G_TYPE_NONE; emission_pop (&g_recursive_emissions, &emission); + if (fastpath_handler) + handler_unref_R (signal_id, instance, fastpath_handler); + SIGNAL_UNLOCK (); if (accumulator) @@ -3267,6 +3274,9 @@ g_signal_emit_valist (gpointer instance, TRACE(GOBJECT_SIGNAL_EMIT_END(signal_id, detail, instance, instance_type)); + if (closure != NULL) + g_object_unref (instance); + return; } }