[libgsystem] fileutil: Add lock around pathname caching



commit 2d24676846e3058d7a03bc127591f9fdcc346fab
Author: Colin Walters <walters verbum org>
Date:   Fri Sep 6 17:17:24 2013 -0400

    fileutil: Add lock around pathname caching
    
    If two threads both call gs_file_get_path_cached() on the same GFile,
    then it's possible that both threads see the pathname isn't cached,
    and set the qdata.  The second one will end up freeing the cached
    qdata from the first, causing it to read freed memory.
    
    Fix this by just slapping a lock around the whole business.
    
    This was observed in the real world in ostree where two threads were
    calling gs_file_get_path_cached() on the shared repo->tmp_dir.
    
    But really, what we want to do is two things:
    
    1) Upstream this into gio
    2) Stop using gs_file_get_path_cached() so much; instead, we
       should be using openat() and friends.  This will also
       avoid malloc, and help us earn our UNIX merit badge.

 gsystem-file-utils.c |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)
---
diff --git a/gsystem-file-utils.c b/gsystem-file-utils.c
index f70239c..6291027 100644
--- a/gsystem-file-utils.c
+++ b/gsystem-file-utils.c
@@ -743,6 +743,8 @@ gs_file_linkcopy_sync_data (GFile          *src,
   return linkcopy_internal (src, dest, flags, TRUE, cancellable, error);
 }
 
+G_LOCK_DEFINE_STATIC (pathname_cache);
+
 /**
  * gs_file_get_path_cached:
  *
@@ -758,6 +760,8 @@ gs_file_get_path_cached (GFile *file)
   if (G_UNLIKELY (_file_path_quark) == 0)
     _file_path_quark = g_quark_from_static_string ("gsystem-file-path");
 
+  G_LOCK (pathname_cache);
+
   path = g_object_get_qdata ((GObject*)file, _file_path_quark);
   if (!path)
     {
@@ -765,6 +769,9 @@ gs_file_get_path_cached (GFile *file)
       g_assert (path != NULL);
       g_object_set_qdata_full ((GObject*)file, _file_path_quark, (char*)path, (GDestroyNotify)g_free);
     }
+
+  G_UNLOCK (pathname_cache);
+
   return path;
 }
 
@@ -783,12 +790,17 @@ gs_file_get_basename_cached (GFile *file)
   if (G_UNLIKELY (_file_name_quark) == 0)
     _file_name_quark = g_quark_from_static_string ("gsystem-file-name");
 
+  G_LOCK (pathname_cache);
+
   name = g_object_get_qdata ((GObject*)file, _file_name_quark);
   if (!name)
     {
       name = g_file_get_basename (file);
       g_object_set_qdata_full ((GObject*)file, _file_name_quark, (char*)name, (GDestroyNotify)g_free);
     }
+
+  G_UNLOCK (pathname_cache);
+
   return name;
 }
 


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