From e9c1c41ac195c885341f7a2e4968a8c62e2ce91a Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Fri, 23 Jan 2015 11:50:26 +0200 Subject: [PATCH] core/device: Fix crash on remove This fixes the following backtrace which was reproduced by removing a device while being connected: Invalid write of size 4 at 0x49AF74: attio_cleanup (device.c:517) by 0x49CB65: att_disconnected_cb (device.c:3811) by 0x4C7485: disconn_handler (att.c:511) by 0x4C415F: queue_foreach (queue.c:251) by 0x4C9379: disconnect_cb (att.c:540) by 0x4D090A: watch_callback (io-glib.c:170) by 0x4E7A2A5: g_main_context_dispatch (in /usr/lib64/libglib-2.0.so.0.3800.2) by 0x4E7A627: ??? (in /usr/lib64/libglib-2.0.so.0.3800.2) by 0x4E7AA39: g_main_loop_run (in /usr/lib64/libglib-2.0.so.0.3800.2) by 0x40BC10: main (main.c:631) Address 0x70db6e8 is 472 bytes inside a block of size 592 free'd at 0x4C28577: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x4E7FF7E: g_free (in /usr/lib64/libglib-2.0.so.0.3800.2) by 0x49C8FF: device_free (device.c:620) by 0x4BE059: remove_interface (object.c:658) by 0x4BEC21: g_dbus_unregister_interface (object.c:1382) by 0x4A4EFC: btd_device_unref (device.c:5185) by 0x474B18: channel_free (attrib-server.c:125) by 0x474BA4: channel_remove (attrib-server.c:986) by 0x47605F: attrib_channel_detach (attrib-server.c:1265) by 0x49AF73: attio_cleanup (device.c:516) by 0x49CB65: att_disconnected_cb (device.c:3811) by 0x4C7485: disconn_handler (att.c:511) --- src/attrib-server.c | 45 +++++++++++++++++---------------------------- src/device.c | 14 +++++++++----- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/src/attrib-server.c b/src/attrib-server.c index aa0012fdf..5f353dfdb 100644 --- a/src/attrib-server.c +++ b/src/attrib-server.c @@ -1223,43 +1223,32 @@ guint attrib_channel_attach(GAttrib *attrib) return channel->id; } -static int channel_id_cmp(gconstpointer data, gconstpointer user_data) +static struct gatt_channel *find_channel(guint id) { - const struct gatt_channel *channel = data; - guint id = GPOINTER_TO_UINT(user_data); - - return channel->id - id; -} - -gboolean attrib_channel_detach(GAttrib *attrib, guint id) -{ - struct gatt_server *server; - struct gatt_channel *channel; - GError *gerr = NULL; - GIOChannel *io; - bdaddr_t src; GSList *l; - io = g_attrib_get_channel(attrib); + for (l = servers; l; l = g_slist_next(l)) { + struct gatt_server *server = l->data; + GSList *c; - bt_io_get(io, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_INVALID); + for (c = server->clients; c; c = g_slist_next(c)) { + struct gatt_channel *channel = c->data; - if (gerr != NULL) { - error("bt_io_get: %s", gerr->message); - g_error_free(gerr); - return FALSE; + if (channel->id == id) + return channel; + } } - server = find_gatt_server(&src); - if (server == NULL) - return FALSE; + return NULL; +} - l = g_slist_find_custom(server->clients, GUINT_TO_POINTER(id), - channel_id_cmp); - if (!l) - return FALSE; +gboolean attrib_channel_detach(GAttrib *attrib, guint id) +{ + struct gatt_channel *channel; - channel = l->data; + channel = find_channel(id); + if (channel == NULL) + return FALSE; g_attrib_unregister(channel->attrib, channel->id); channel_remove(channel); diff --git a/src/device.c b/src/device.c index 59e4dea3d..2a5a88309 100644 --- a/src/device.c +++ b/src/device.c @@ -512,11 +512,6 @@ static void gatt_client_cleanup(struct btd_device *device) static void attio_cleanup(struct btd_device *device) { - if (device->attachid) { - attrib_channel_detach(device->attrib, device->attachid); - device->attachid = 0; - } - if (device->att_disconn_id) bt_att_unregister_disconnect(device->att, device->att_disconn_id); @@ -536,7 +531,16 @@ static void attio_cleanup(struct btd_device *device) if (device->attrib) { GAttrib *attrib = device->attrib; + device->attrib = NULL; + + if (device->attachid) { + guint attachid = device->attachid; + + device->attachid = 0; + attrib_channel_detach(attrib, attachid); + } + g_attrib_cancel_all(attrib); g_attrib_unref(attrib); } -- 2.47.3