summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.co.uk>2012-01-11 15:30:51 +0100
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2012-02-02 17:08:12 +0000
commit7f8d540689172bfd697e6d22775a94cc73259a3f (patch)
treec5cd208baac7ce7a0dd49c22bb337a0ce1999b56
parent0ca5332db718340aa8546cd828b138c411a99adf (diff)
downloadtelepathy-glib-7f8d540689172bfd697e6d22775a94cc73259a3f.tar.gz
channel-contacts.c: Fix crash when preparing TpCallChannel
If if a new contact fetch is queued from the callback of last contact fetch, it leads to a crash. This is because when queueing the new item it is processed right away since it is the only item in queue, then when it returns from g_simple_async_result_complete() it calls process_contacts_queue() again so the item is prepared twice, and then freed twice. Fix this by keeping currently being processes item outside the queue.
-rw-r--r--telepathy-glib/channel-contacts.c22
-rw-r--r--telepathy-glib/channel-internal.h4
2 files changed, 15 insertions, 11 deletions
diff --git a/telepathy-glib/channel-contacts.c b/telepathy-glib/channel-contacts.c
index 3e5fdd6c9..efefe38b7 100644
--- a/telepathy-glib/channel-contacts.c
+++ b/telepathy-glib/channel-contacts.c
@@ -232,13 +232,13 @@ _tp_channel_contacts_group_init (TpChannel *self,
}
}
-typedef struct
+struct _ContactsQueueItem
{
GSimpleAsyncResult *result;
GPtrArray *contacts;
GPtrArray *ids;
GArray *handles;
-} ContactsQueueItem;
+};
static ContactsQueueItem *
contacts_queue_item_new (GPtrArray *contacts,
@@ -273,9 +273,7 @@ static void
contacts_queue_head_ready (TpChannel *self,
const GError *error)
{
- ContactsQueueItem *item;
-
- item = g_queue_pop_head (self->priv->contacts_queue);
+ ContactsQueueItem *item = self->priv->current_item;
if (error != NULL)
{
@@ -284,6 +282,7 @@ contacts_queue_head_ready (TpChannel *self,
}
g_simple_async_result_complete (item->result);
+ self->priv->current_item = NULL;
process_contacts_queue (self);
contacts_queue_item_free (item);
@@ -366,8 +365,7 @@ process_contacts_queue (TpChannel *self)
GArray *features;
const GError *error = NULL;
- item = g_queue_peek_head (self->priv->contacts_queue);
- if (item == NULL)
+ if (self->priv->current_item != NULL)
return;
/* self can't die while there are queued items because item->result keeps a
@@ -387,6 +385,11 @@ process_contacts_queue (TpChannel *self)
return;
}
+ item = g_queue_pop_head (self->priv->contacts_queue);
+ if (item == NULL)
+ return;
+ self->priv->current_item = item;
+
features = tp_simple_client_factory_dup_contact_features (
tp_proxy_get_factory (self->priv->connection), self->priv->connection);
@@ -450,10 +453,7 @@ contacts_queue_item (TpChannel *self,
g_simple_async_result_set_op_res_gpointer (item->result, item, NULL);
g_queue_push_tail (self->priv->contacts_queue, item);
-
- /* If this is the only item in the queue, we can process it right away */
- if (self->priv->contacts_queue->length == 1)
- process_contacts_queue (self);
+ process_contacts_queue (self);
}
void
diff --git a/telepathy-glib/channel-internal.h b/telepathy-glib/channel-internal.h
index 312dfe633..0f13666d2 100644
--- a/telepathy-glib/channel-internal.h
+++ b/telepathy-glib/channel-internal.h
@@ -35,6 +35,8 @@ typedef struct {
gchar *message;
} LocalPendingInfo;
+typedef struct _ContactsQueueItem ContactsQueueItem;
+
struct _TpChannelPrivate {
gulong conn_invalidated_id;
@@ -87,6 +89,8 @@ struct _TpChannelPrivate {
gboolean cm_too_old_for_contacts;
GQueue *contacts_queue;
+ /* Item currently being prepared, not part of contacts_queue anymore */
+ ContactsQueueItem *current_item;
/* NULL, or TpHandle => TpChannelChatState;
* if non-NULL, we're watching for ChatStateChanged */