When processing inotify events, callbacks may unregister which can
result in freeing the related connman_inotify struct. However that
struct is referenced in the loop which processes the events read in.

Implement reference counting to make sure the structure is available
while events are being processed.
---
 src/inotify.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/src/inotify.c b/src/inotify.c
index 12fcb7d..485b7ed 100644
--- a/src/inotify.c
+++ b/src/inotify.c
@@ -35,6 +35,8 @@
 #include "connman.h"
 
 struct connman_inotify {
+       unsigned int refcount;
+
        GIOChannel *channel;
        uint watch;
        int wd;
@@ -42,6 +44,21 @@ struct connman_inotify {
        GSList *list;
 };
 
+static void cleanup_inotify(gpointer user_data);
+
+static void connman_inotify_ref(struct connman_inotify *i)
+{
+       __sync_fetch_and_add(&i->refcount, 1);
+}
+
+static void connman_inotify_unref(gpointer data)
+{
+       struct connman_inotify *i = data;
+       if (__sync_fetch_and_sub(&i->refcount, 1) != 1)
+               return;
+       cleanup_inotify(data);
+}
+
 static GHashTable *inotify_hash;
 
 static gboolean inotify_data(GIOChannel *channel, GIOCondition cond,
@@ -75,6 +92,8 @@ static gboolean inotify_data(GIOChannel *channel, 
GIOCondition cond,
 
        next_event = buffer;
 
+       connman_inotify_ref(inotify);
+
        while (bytes_read > 0) {
                struct inotify_event *event;
                gchar *ident;
@@ -102,6 +121,8 @@ static gboolean inotify_data(GIOChannel *channel, 
GIOCondition cond,
                }
        }
 
+       connman_inotify_unref(inotify);
+
        return TRUE;
 }
 
@@ -179,6 +200,7 @@ int connman_inotify_register(const char *path, 
inotify_event_cb callback)
        if (!inotify)
                return -ENOMEM;
 
+       inotify->refcount = 1;
        inotify->wd = -1;
 
        err = create_watch(path, inotify);
@@ -225,7 +247,7 @@ int __connman_inotify_init(void)
        DBG("");
 
        inotify_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
-                                               g_free, cleanup_inotify);
+                                               g_free, connman_inotify_unref);
        return 0;
 }
 
-- 
1.9.1

_______________________________________________
connman mailing list
connman@connman.net
https://lists.connman.net/mailman/listinfo/connman

Reply via email to