Calling ofono_remove_modem() while iterating the hash table is not safe
given that it can modify the table in hfp_remove().

A simple way to reproduce the problem is to pair some Bluetooth phones
and remove the Bluetooth adapter, triggering a GLib-CRITICAL assertion.

This approach proposes a two-step removal: first, the hash table is
iterated and all modems to be removed are marked as pending (thus
removed from the hash table and put in a temporary list), and afterwards
all pending modems are actually removed.
---
 plugins/hfp_hf.c |   11 ++++++++++-
 1 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/plugins/hfp_hf.c b/plugins/hfp_hf.c
index 48a734a..0028e21 100644
--- a/plugins/hfp_hf.c
+++ b/plugins/hfp_hf.c
@@ -60,6 +60,7 @@
 
 static DBusConnection *connection;
 static GHashTable *modem_hash = NULL;
+static GSList *pending_removals = NULL;
 
 struct hfp_data {
        struct hfp_slc_info info;
@@ -265,11 +266,16 @@ static gboolean hfp_remove_modem(gpointer key, gpointer 
value,
        if (prefix && g_str_has_prefix(device, prefix) == FALSE)
                return FALSE;
 
-       ofono_modem_remove(modem);
+       pending_removals = g_slist_append(pending_removals, modem);
 
        return TRUE;
 }
 
+static void hfp_remove_pending_modem(gpointer data)
+{
+       ofono_modem_remove(data);
+}
+
 static void hfp_hf_remove(const char *prefix)
 {
        DBG("%s", prefix);
@@ -279,6 +285,9 @@ static void hfp_hf_remove(const char *prefix)
 
        g_hash_table_foreach_remove(modem_hash, hfp_remove_modem,
                                                        (gpointer) prefix);
+
+       g_slist_free_full(pending_removals, hfp_remove_pending_modem);
+       pending_removals = NULL;
 }
 
 static void hfp_hf_set_alias(const char *device, const char *alias)
-- 
1.7.7.6

_______________________________________________
ofono mailing list
[email protected]
http://lists.ofono.org/listinfo/ofono

Reply via email to