[gnome-menus] entry-directories: don't modify a list while iterating it



commit 27b7c7100e007764acf56d91dc76474099f3f1b3
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Sat Dec 14 15:16:09 2013 +0100

    entry-directories: don't modify a list while iterating it
    
    cached_dir_unref() tries to remove the directory from the parent's
    list of subdirectories, but it is also called when the parent is
    being freed and iterating with foreach() on its directory list.
    This is unsafe, so don't do it.
    Also, fix the logic for remove_subdir() to unref() only when it's
    right to do so (ie, always, when the function is called, because
    everything keeps strong references).
    
    https://bugzilla.gnome.org/show_bug.cgi?id=720460

 libmenu/entry-directories.c |   22 ++++++++++++++++------
 1 files changed, 16 insertions(+), 6 deletions(-)
---
diff --git a/libmenu/entry-directories.c b/libmenu/entry-directories.c
index 6af3850..52ddfd8 100644
--- a/libmenu/entry-directories.c
+++ b/libmenu/entry-directories.c
@@ -83,6 +83,7 @@ static void     cached_dir_free                   (CachedDir  *dir);
 static gboolean cached_dir_load_entries_recursive (CachedDir  *dir,
                                                    const char *dirname);
 static void     cached_dir_unref                  (CachedDir *dir);
+static void     cached_dir_unref_noparent         (CachedDir *dir);
 static CachedDir * cached_dir_add_subdir          (CachedDir  *dir,
                                                    const char *basename,
                                                    const char *path);
@@ -156,7 +157,7 @@ cached_dir_free (CachedDir *dir)
   dir->entries = NULL;
 
   g_slist_foreach (dir->subdirs,
-                   (GFunc) cached_dir_unref,
+                   (GFunc) cached_dir_unref_noparent,
                    NULL);
   g_slist_free (dir->subdirs);
   dir->subdirs = NULL;
@@ -191,6 +192,18 @@ cached_dir_unref (CachedDir *dir)
     }
 }
 
+static void
+cached_dir_unref_noparent (CachedDir *dir)
+{
+  if (--dir->references == 0)
+    {
+      if (dir->notify)
+        dir->notify (dir, dir->notify_data);
+
+      cached_dir_free (dir);
+    }
+}
+
 static inline CachedDir *
 find_subdir (CachedDir  *dir,
              const char *subdir)
@@ -406,11 +419,8 @@ cached_dir_remove_subdir (CachedDir  *dir,
     {
       subdir->deleted = TRUE;
 
-      if (subdir->references == 0)
-        {
-          cached_dir_unref (subdir);
-          dir->subdirs = g_slist_remove (dir->subdirs, subdir);
-        }
+      cached_dir_unref (subdir);
+      dir->subdirs = g_slist_remove (dir->subdirs, subdir);
 
       return TRUE;
     }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]