summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2013-09-06 17:17:24 -0400
committerColin Walters <walters@verbum.org>2013-09-06 18:22:19 -0400
commit2d24676846e3058d7a03bc127591f9fdcc346fab (patch)
tree0e67b5898a8a61765cb0ea20b23d407577041233
parent870b672bb28e4c8cf4ba86075ba24b4dd5b85f42 (diff)
downloadlibgsystem-2d24676846e3058d7a03bc127591f9fdcc346fab.tar.gz
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.
-rw-r--r--gsystem-file-utils.c12
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;
}