diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2012-08-07 16:22:41 +0100 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2012-08-07 16:25:27 +0100 |
commit | 7c2e6c31419fe6cc66c90361c36d9ff0b6a148f9 (patch) | |
tree | a875a763ea151f026830b73ed1be4811b1c8a892 | |
parent | d19b6dd129492ca0de2073d84d5af96462d9c934 (diff) |
YtsContact: don't crash if our contact or one of our services outlives us
If the TpContact or one of the YtsService instances still exists after
the YtsContact has been freed, and emits a signal to which the YtsContact
is still subscribing, then we would crash with a use-after-free.
Disconnect all of our signals to avoid that fate.
-rw-r--r-- | ytstenut/yts-contact.c | 35 |
1 files changed, 27 insertions, 8 deletions
diff --git a/ytstenut/yts-contact.c b/ytstenut/yts-contact.c index 26457dc..ac533d8 100644 --- a/ytstenut/yts-contact.c +++ b/ytstenut/yts-contact.c @@ -229,12 +229,27 @@ _set_property (GObject *object, static void _dispose (GObject *object) { + YtsContact *self = YTS_CONTACT (object); YtsContactPrivate *priv = GET_PRIVATE (object); - if (priv->services) { - g_hash_table_destroy (priv->services); - priv->services = NULL; - } + if (priv->services) + { + GHashTableIter iter; + gpointer k, v; + + g_hash_table_iter_init (&iter, priv->services); + + while (g_hash_table_iter_next (&iter, &k, &v)) + { + g_signal_handlers_disconnect_by_func (v, _service_send_message, + self); + g_signal_handlers_disconnect_by_func (v, _service_send_file, + self); + } + + g_hash_table_destroy (priv->services); + priv->services = NULL; + } if (priv->deferred_service_statuses) { g_hash_table_destroy (priv->deferred_service_statuses); @@ -242,10 +257,14 @@ _dispose (GObject *object) } // FIXME tie to tp_contact lifecycle - if (priv->tp_contact) { - g_object_unref (priv->tp_contact); - priv->tp_contact = NULL; - } + if (priv->tp_contact) + { + g_signal_handlers_disconnect_by_func (priv->tp_contact, + _tp_contact_notify_alias, self); + + g_object_unref (priv->tp_contact); + priv->tp_contact = NULL; + } G_OBJECT_CLASS (yts_contact_parent_class)->dispose (object); } |