summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2012-08-07 16:22:41 +0100
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2012-08-07 16:25:27 +0100
commit7c2e6c31419fe6cc66c90361c36d9ff0b6a148f9 (patch)
treea875a763ea151f026830b73ed1be4811b1c8a892
parentd19b6dd129492ca0de2073d84d5af96462d9c934 (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.c35
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);
}