gutils: Don’t read directory globals outside the lock

While it is currently OK to read the global variables backing functions
like g_get_user_data_dir() without the g_utils_global lock held (since
such a read is always preceeded by a critical section where the variable
is set to its final value), upcoming changes will allow those variables
to be changed. If they are changed from one thread while another thread
is calling (for example) g_get_user_data_dir(), the final read from the
second thread could race with the first thread.

Avoid that by only reading the global variables with the lock held.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

https://gitlab.gnome.org/GNOME/glib/issues/538
This commit is contained in:
Philip Withnall 2018-11-30 17:36:44 +00:00
parent 8da50ac40c
commit b87dfb4960

View File

@ -555,13 +555,13 @@ typedef struct
gchar *home_dir; gchar *home_dir;
} UserDatabaseEntry; } UserDatabaseEntry;
/* These must all be read/written with @g_utils_global held. */
static gchar *g_user_data_dir = NULL; static gchar *g_user_data_dir = NULL;
static gchar **g_system_data_dirs = NULL; static gchar **g_system_data_dirs = NULL;
static gchar *g_user_cache_dir = NULL; static gchar *g_user_cache_dir = NULL;
static gchar *g_user_config_dir = NULL; static gchar *g_user_config_dir = NULL;
static gchar *g_user_runtime_dir = NULL; static gchar *g_user_runtime_dir = NULL;
static gchar **g_system_config_dirs = NULL; static gchar **g_system_config_dirs = NULL;
static gchar **g_user_special_dirs = NULL; static gchar **g_user_special_dirs = NULL;
/* fifteen minutes of fame for everybody */ /* fifteen minutes of fame for everybody */
@ -823,6 +823,8 @@ static gchar *g_home_dir = NULL; /* (owned) (nullable before initialised) */
const gchar * const gchar *
g_get_home_dir (void) g_get_home_dir (void)
{ {
const gchar *home_dir;
G_LOCK (g_utils_global); G_LOCK (g_utils_global);
if (g_home_dir == NULL) if (g_home_dir == NULL)
@ -905,9 +907,11 @@ g_get_home_dir (void)
g_home_dir = g_steal_pointer (&tmp); g_home_dir = g_steal_pointer (&tmp);
} }
home_dir = g_home_dir;
G_UNLOCK (g_utils_global); G_UNLOCK (g_utils_global);
return g_home_dir; return home_dir;
} }
/** /**
@ -1223,14 +1227,17 @@ g_build_user_data_dir (void)
const gchar * const gchar *
g_get_user_data_dir (void) g_get_user_data_dir (void)
{ {
const gchar *user_data_dir;
G_LOCK (g_utils_global); G_LOCK (g_utils_global);
if (g_user_data_dir == NULL) if (g_user_data_dir == NULL)
g_user_data_dir = g_build_user_data_dir (); g_user_data_dir = g_build_user_data_dir ();
user_data_dir = g_user_data_dir;
G_UNLOCK (g_utils_global); G_UNLOCK (g_utils_global);
return g_user_data_dir; return user_data_dir;
} }
static gchar * static gchar *
@ -1283,14 +1290,17 @@ g_build_user_config_dir (void)
const gchar * const gchar *
g_get_user_config_dir (void) g_get_user_config_dir (void)
{ {
const gchar *user_config_dir;
G_LOCK (g_utils_global); G_LOCK (g_utils_global);
if (g_user_config_dir == NULL) if (g_user_config_dir == NULL)
g_user_config_dir = g_build_user_config_dir (); g_user_config_dir = g_build_user_config_dir ();
user_config_dir = g_user_config_dir;
G_UNLOCK (g_utils_global); G_UNLOCK (g_utils_global);
return g_user_config_dir; return user_config_dir;
} }
static gchar * static gchar *
@ -1342,14 +1352,17 @@ g_build_user_cache_dir (void)
const gchar * const gchar *
g_get_user_cache_dir (void) g_get_user_cache_dir (void)
{ {
const gchar *user_cache_dir;
G_LOCK (g_utils_global); G_LOCK (g_utils_global);
if (g_user_cache_dir == NULL) if (g_user_cache_dir == NULL)
g_user_cache_dir = g_build_user_cache_dir (); g_user_cache_dir = g_build_user_cache_dir ();
user_cache_dir = g_user_cache_dir;
G_UNLOCK (g_utils_global); G_UNLOCK (g_utils_global);
return g_user_cache_dir; return user_cache_dir;
} }
static gchar * static gchar *
@ -1402,14 +1415,17 @@ g_build_user_runtime_dir (void)
const gchar * const gchar *
g_get_user_runtime_dir (void) g_get_user_runtime_dir (void)
{ {
const gchar *user_runtime_dir;
G_LOCK (g_utils_global); G_LOCK (g_utils_global);
if (g_user_runtime_dir == NULL) if (g_user_runtime_dir == NULL)
g_user_runtime_dir = g_build_user_runtime_dir (); g_user_runtime_dir = g_build_user_runtime_dir ();
user_runtime_dir = g_user_runtime_dir;
G_UNLOCK (g_utils_global); G_UNLOCK (g_utils_global);
return g_user_runtime_dir; return user_runtime_dir;
} }
#ifdef HAVE_CARBON #ifdef HAVE_CARBON
@ -1774,6 +1790,8 @@ g_reload_user_special_dirs_cache (void)
const gchar * const gchar *
g_get_user_special_dir (GUserDirectory directory) g_get_user_special_dir (GUserDirectory directory)
{ {
const gchar *user_special_dir;
g_return_val_if_fail (directory >= G_USER_DIRECTORY_DESKTOP && g_return_val_if_fail (directory >= G_USER_DIRECTORY_DESKTOP &&
directory < G_USER_N_DIRECTORIES, NULL); directory < G_USER_N_DIRECTORIES, NULL);
@ -1789,10 +1807,11 @@ g_get_user_special_dir (GUserDirectory directory)
if (g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] == NULL) if (g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] == NULL)
g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] = g_build_filename (g_get_home_dir (), "Desktop", NULL); g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] = g_build_filename (g_get_home_dir (), "Desktop", NULL);
} }
user_special_dir = g_user_special_dirs[directory];
G_UNLOCK (g_utils_global); G_UNLOCK (g_utils_global);
return g_user_special_dirs[directory]; return user_special_dir;
} }
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
@ -2066,14 +2085,17 @@ g_build_system_data_dirs (void)
const gchar * const * const gchar * const *
g_get_system_data_dirs (void) g_get_system_data_dirs (void)
{ {
const gchar * const *system_data_dirs;
G_LOCK (g_utils_global); G_LOCK (g_utils_global);
if (g_system_data_dirs == NULL) if (g_system_data_dirs == NULL)
g_system_data_dirs = g_build_system_data_dirs (); g_system_data_dirs = g_build_system_data_dirs ();
system_data_dirs = (const gchar * const *) g_system_data_dirs;
G_UNLOCK (g_utils_global); G_UNLOCK (g_utils_global);
return (const gchar * const *) g_system_data_dirs; return system_data_dirs;
} }
static gchar ** static gchar **
@ -2138,14 +2160,17 @@ g_build_system_config_dirs (void)
const gchar * const * const gchar * const *
g_get_system_config_dirs (void) g_get_system_config_dirs (void)
{ {
const gchar * const *system_config_dirs;
G_LOCK (g_utils_global); G_LOCK (g_utils_global);
if (g_system_config_dirs == NULL) if (g_system_config_dirs == NULL)
g_system_config_dirs = g_build_system_config_dirs (); g_system_config_dirs = g_build_system_config_dirs ();
system_config_dirs = (const gchar * const *) g_system_config_dirs;
G_UNLOCK (g_utils_global); G_UNLOCK (g_utils_global);
return (const gchar * const *) g_system_config_dirs; return system_config_dirs;
} }
/** /**