From 1e0632dcffc06127e9919fcd4dfa3571108ff0de Mon Sep 17 00:00:00 2001 From: Mike Ruprecht Date: Tue, 13 Oct 2009 18:40:52 -0500 Subject: Cancel outstanding channel requests if connection to the CM is lost. When the connection to a given channel manager was lost (such as it crashed), any outstanding channel requests were freed, but then the request callback fired with an invalid (already freed) DispatcherRequestData parameter. It subsequently used this invalid data and crashed. This patch cancels all outstanding channel requests when they are freed so the callback isn't called with invalid data. Fixes #598332 --- libempathy/empathy-dispatcher.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/libempathy/empathy-dispatcher.c b/libempathy/empathy-dispatcher.c index 57c79c2e0..2655764f8 100644 --- a/libempathy/empathy-dispatcher.c +++ b/libempathy/empathy-dispatcher.c @@ -131,6 +131,7 @@ typedef struct guint handle_type; guint handle; EmpathyContact *contact; + TpProxyPendingCall *pending_call; /* Properties to pass to the channel when requesting it */ GHashTable *request; @@ -284,6 +285,8 @@ free_connection_data (ConnectionData *cd) for (l = cd->outstanding_requests ; l != NULL; l = g_list_delete_link (l,l)) { + DispatcherRequestData *data = l->data; + tp_proxy_pending_call_cancel (data->pending_call); free_dispatcher_request_data (l->data); } @@ -1322,7 +1325,8 @@ dispatcher_request_channel (DispatcherRequestData *request_data) } else { - tp_cli_connection_call_request_channel (request_data->connection, -1, + request_data->pending_call = tp_cli_connection_call_request_channel ( + request_data->connection, -1, request_data->channel_type, request_data->handle_type, request_data->handle, @@ -1481,7 +1485,8 @@ empathy_dispatcher_join_muc (TpConnection *connection, connection_data->outstanding_requests = g_list_prepend (connection_data->outstanding_requests, request_data); - tp_cli_connection_call_request_handles (connection, -1, + request_data->pending_call = tp_cli_connection_call_request_handles ( + connection, -1, TP_HANDLE_TYPE_ROOM, names, dispatcher_request_handles_cb, request_data, NULL, G_OBJECT (dispatcher)); @@ -1527,14 +1532,16 @@ empathy_dispatcher_call_create_or_ensure_channel ( { if (request_data->should_ensure) { - tp_cli_connection_interface_requests_call_ensure_channel ( + request_data->pending_call = + tp_cli_connection_interface_requests_call_ensure_channel ( request_data->connection, -1, request_data->request, dispatcher_ensure_channel_cb, request_data, NULL, G_OBJECT (request_data->dispatcher)); } else { - tp_cli_connection_interface_requests_call_create_channel ( + request_data->pending_call = + tp_cli_connection_interface_requests_call_create_channel ( request_data->connection, -1, request_data->request, dispatcher_create_channel_cb, request_data, NULL, G_OBJECT (request_data->dispatcher)); -- cgit v1.2.3 From eeafe98a27dbccc08a6023b7c73f7bd537c5e39c Mon Sep 17 00:00:00 2001 From: Mike Ruprecht Date: Wed, 14 Oct 2009 16:23:43 -0500 Subject: Remove the weak_object parameter when requesting channels. Use the EmpathyDispatcher pointed to in the DispatcherRequestData instead of the weak_object. Outstanding channel requests were being cancelled in the EmpathyDispatcher's finalize method. This had the potential to double-cancel the requests when the weak_object (EmpathyDispatcher) was unreffed, causing a segmentation fault. --- libempathy/empathy-dispatcher.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/libempathy/empathy-dispatcher.c b/libempathy/empathy-dispatcher.c index 2655764f8..55f2e7579 100644 --- a/libempathy/empathy-dispatcher.c +++ b/libempathy/empathy-dispatcher.c @@ -1294,8 +1294,9 @@ dispatcher_request_channel_cb (TpConnection *connection, gpointer user_data, GObject *weak_object) { - EmpathyDispatcher *dispatcher = EMPATHY_DISPATCHER (weak_object); DispatcherRequestData *request_data = (DispatcherRequestData *) user_data; + EmpathyDispatcher *dispatcher = + EMPATHY_DISPATCHER (request_data->dispatcher); dispatcher_connection_new_requested_channel (dispatcher, request_data, object_path, NULL, error); @@ -1331,7 +1332,7 @@ dispatcher_request_channel (DispatcherRequestData *request_data) request_data->handle_type, request_data->handle, TRUE, dispatcher_request_channel_cb, - request_data, NULL, G_OBJECT (request_data->dispatcher)); + request_data, NULL, NULL); } } @@ -1488,8 +1489,7 @@ empathy_dispatcher_join_muc (TpConnection *connection, request_data->pending_call = tp_cli_connection_call_request_handles ( connection, -1, TP_HANDLE_TYPE_ROOM, names, - dispatcher_request_handles_cb, request_data, NULL, - G_OBJECT (dispatcher)); + dispatcher_request_handles_cb, request_data, NULL, NULL); g_object_unref (dispatcher); } @@ -1502,8 +1502,9 @@ dispatcher_create_channel_cb (TpConnection *connect, gpointer user_data, GObject *weak_object) { - EmpathyDispatcher *dispatcher = EMPATHY_DISPATCHER (weak_object); DispatcherRequestData *request_data = (DispatcherRequestData *) user_data; + EmpathyDispatcher *dispatcher = + EMPATHY_DISPATCHER (request_data->dispatcher); dispatcher_connection_new_requested_channel (dispatcher, request_data, object_path, properties, error); @@ -1518,8 +1519,9 @@ dispatcher_ensure_channel_cb (TpConnection *connect, gpointer user_data, GObject *weak_object) { - EmpathyDispatcher *dispatcher = EMPATHY_DISPATCHER (weak_object); DispatcherRequestData *request_data = (DispatcherRequestData *) user_data; + EmpathyDispatcher *dispatcher = + EMPATHY_DISPATCHER (request_data->dispatcher); dispatcher_connection_new_requested_channel (dispatcher, request_data, object_path, properties, error); @@ -1536,7 +1538,7 @@ empathy_dispatcher_call_create_or_ensure_channel ( tp_cli_connection_interface_requests_call_ensure_channel ( request_data->connection, -1, request_data->request, dispatcher_ensure_channel_cb, - request_data, NULL, G_OBJECT (request_data->dispatcher)); + request_data, NULL, NULL); } else { @@ -1544,7 +1546,7 @@ empathy_dispatcher_call_create_or_ensure_channel ( tp_cli_connection_interface_requests_call_create_channel ( request_data->connection, -1, request_data->request, dispatcher_create_channel_cb, - request_data, NULL, G_OBJECT (request_data->dispatcher)); + request_data, NULL, NULL); } } -- cgit v1.2.3 From 21236da0d1d89af62dd4e11e883b553af658f41a Mon Sep 17 00:00:00 2001 From: Mike Ruprecht Date: Wed, 14 Oct 2009 16:59:04 -0500 Subject: Move destruction of connections from finalize to dispose. Code can potentially be run between the dispose and finalize methods. This moves the destruction of connections and subsequently outstanding_requests into the dispose function so the request callback can't be fired between unreffing the EmpathyDispatcher and cancelling the pending request. --- libempathy/empathy-dispatcher.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/libempathy/empathy-dispatcher.c b/libempathy/empathy-dispatcher.c index 55f2e7579..cc0c8198b 100644 --- a/libempathy/empathy-dispatcher.c +++ b/libempathy/empathy-dispatcher.c @@ -944,6 +944,8 @@ static void dispatcher_dispose (GObject *object) { EmpathyDispatcherPriv *priv = GET_PRIV (object); + GHashTableIter iter; + gpointer connection; GList *l; if (priv->dispose_has_run) @@ -961,6 +963,16 @@ dispatcher_dispose (GObject *object) g_object_unref (priv->handler); priv->handler = NULL; + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, &connection, NULL)) + { + g_signal_handlers_disconnect_by_func (connection, + dispatcher_connection_invalidated_cb, object); + } + + g_hash_table_destroy (priv->connections); + priv->connections = NULL; + G_OBJECT_CLASS (empathy_dispatcher_parent_class)->dispose (object); } @@ -991,13 +1003,6 @@ dispatcher_finalize (GObject *object) g_list_free (priv->channels); - g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, &connection, NULL)) - { - g_signal_handlers_disconnect_by_func (connection, - dispatcher_connection_invalidated_cb, object); - } - g_hash_table_iter_init (&iter, priv->outstanding_classes_requests); while (g_hash_table_iter_next (&iter, &connection, (gpointer *) &list)) { @@ -1007,7 +1012,6 @@ dispatcher_finalize (GObject *object) g_object_unref (priv->account_manager); - g_hash_table_destroy (priv->connections); g_hash_table_destroy (priv->outstanding_classes_requests); } -- cgit v1.2.3