diff options
author | Philip Withnall <philip.withnall@collabora.co.uk> | 2010-08-05 19:53:37 +0800 |
---|---|---|
committer | Philip Withnall <philip.withnall@collabora.co.uk> | 2010-08-05 22:25:29 +0800 |
commit | 439b05f9d36c750da3e490a8667dde2aeeb06e52 (patch) | |
tree | a32e0d4cbc77e1b17dfa5d3ebb96cd2f6159c45a | |
parent | bd7b9b376ea305ca57bb0beab6bfae8a82d69012 (diff) | |
download | gsoc2013-empathy-439b05f9d36c750da3e490a8667dde2aeeb06e52.tar gsoc2013-empathy-439b05f9d36c750da3e490a8667dde2aeeb06e52.tar.gz gsoc2013-empathy-439b05f9d36c750da3e490a8667dde2aeeb06e52.tar.bz2 gsoc2013-empathy-439b05f9d36c750da3e490a8667dde2aeeb06e52.tar.lz gsoc2013-empathy-439b05f9d36c750da3e490a8667dde2aeeb06e52.tar.xz gsoc2013-empathy-439b05f9d36c750da3e490a8667dde2aeeb06e52.tar.zst gsoc2013-empathy-439b05f9d36c750da3e490a8667dde2aeeb06e52.zip |
Fix memory corruption introduced by not removing a weak pointer
This rewrites the weak pointer code for active individuals in
EmpathyIndividualStore to use weak references, which has the added benefit of
meaning we can remove the timeout if the individual disappears, rather than
executing it anyway and just bailing out. Closes: bgo#625641
-rw-r--r-- | libempathy-gtk/empathy-individual-store.c | 56 |
1 files changed, 39 insertions, 17 deletions
diff --git a/libempathy-gtk/empathy-individual-store.c b/libempathy-gtk/empathy-individual-store.c index 574ae2b58..0a628855c 100644 --- a/libempathy-gtk/empathy-individual-store.c +++ b/libempathy-gtk/empathy-individual-store.c @@ -92,6 +92,7 @@ typedef struct EmpathyIndividualStore *self; FolksIndividual *individual; gboolean remove; + guint timeout; } ShowActiveData; enum @@ -464,6 +465,26 @@ individual_store_contact_set_active (EmpathyIndividualStore *self, } +static void individual_store_contact_active_free (ShowActiveData *data); + +static void +individual_store_contact_active_invalidated (ShowActiveData *data, + GObject *old_object) +{ + /* Remove the timeout and free the struct, since the individual or individual + * store has disappeared. */ + g_source_remove (data->timeout); + + if (old_object == (GObject *)data->self) + data->self = NULL; + else if (old_object == (GObject *)data->individual) + data->individual = NULL; + else + g_assert_not_reached (); + + individual_store_contact_active_free (data); +} + static ShowActiveData * individual_store_contact_active_new (EmpathyIndividualStore *self, FolksIndividual *individual, @@ -479,13 +500,15 @@ individual_store_contact_active_new (EmpathyIndividualStore *self, /* We don't actually want to force either the IndividualStore or the * Individual to stay alive, since the user could quit Empathy or disable * the account before the contact_active timeout is fired. */ - g_object_add_weak_pointer (G_OBJECT (self), (gpointer) &(data->self)); - g_object_add_weak_pointer (G_OBJECT (individual), - (gpointer) &(data->individual)); + g_object_weak_ref (G_OBJECT (self), + (GWeakNotify) individual_store_contact_active_invalidated, data); + g_object_weak_ref (G_OBJECT (individual), + (GWeakNotify) individual_store_contact_active_invalidated, data); data->self = self; data->individual = individual; data->remove = remove_; + data->timeout = 0; return data; } @@ -493,25 +516,24 @@ individual_store_contact_active_new (EmpathyIndividualStore *self, static void individual_store_contact_active_free (ShowActiveData *data) { + if (data->self != NULL) + { + g_object_weak_unref (G_OBJECT (data->self), + (GWeakNotify) individual_store_contact_active_invalidated, data); + } + + if (data->individual != NULL) + { + g_object_weak_unref (G_OBJECT (data->individual), + (GWeakNotify) individual_store_contact_active_invalidated, data); + } + g_slice_free (ShowActiveData, data); } static gboolean individual_store_contact_active_cb (ShowActiveData *data) { - EmpathyIndividualStorePriv *priv; - - /* They're weak pointers, so may have been NULLified between ShowActiveData - * being created and the timeout being fired. We assume they can only be - * destroyed in this thread, so this isn't MT-safe. */ - if (data->self == NULL || data->individual == NULL) - { - individual_store_contact_active_free (data); - return FALSE; - } - - priv = GET_PRIV (data->self); - if (data->remove) { DEBUG ("Individual'%s' active timeout, removing item", @@ -702,7 +724,7 @@ individual_store_contact_update (EmpathyIndividualStore *self, data = individual_store_contact_active_new (self, individual, do_remove); - g_timeout_add_seconds (ACTIVE_USER_SHOW_TIME, + data->timeout = g_timeout_add_seconds (ACTIVE_USER_SHOW_TIME, (GSourceFunc) individual_store_contact_active_cb, data); } } |