summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkira TAGOH <akira@tagoh.org>2019-11-02 00:14:48 +0900
committerAkira TAGOH <akira@tagoh.org>2019-11-06 14:21:34 +0900
commitaa8c8cfa9fb2563482336249e3f56459099fcf6e (patch)
tree06f73d068d2ad45bfa97e815caeb8fb4164294ed
parentb5bcf61fe789e66df2de609ec246cb7e4d326180 (diff)
Fix potential race condition in FcConfigSetCurrent and FcConfigReference
-rw-r--r--src/fccache.c2
-rw-r--r--src/fccfg.c105
2 files changed, 90 insertions, 17 deletions
diff --git a/src/fccache.c b/src/fccache.c
index d8f1dab..4744a84 100644
--- a/src/fccache.c
+++ b/src/fccache.c
@@ -1085,6 +1085,8 @@ FcDirCacheLoadFile (const FcChar8 *cache_file, struct stat *file_stat)
if (fd < 0)
return NULL;
config = FcConfigReference (NULL);
+ if (!config)
+ return NULL;
cache = FcDirCacheMapFd (config, fd, file_stat, NULL);
FcConfigDestroy (config);
close (fd);
diff --git a/src/fccfg.c b/src/fccfg.c
index 11dc876..30f37af 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -33,6 +33,49 @@
#endif
static FcConfig *_fcConfig; /* MT-safe */
+static FcMutex *_lock;
+
+static void
+lock_config (void)
+{
+ FcMutex *lock;
+retry:
+ lock = fc_atomic_ptr_get (&_lock);
+ if (!lock)
+ {
+ lock = (FcMutex *) malloc (sizeof (FcMutex));
+ FcMutexInit (lock);
+ if (!fc_atomic_ptr_cmpexch (&_lock, NULL, lock))
+ {
+ FcMutexFinish (lock);
+ goto retry;
+ }
+ FcMutexLock (lock);
+ /* Initialize random state */
+ FcRandom ();
+ return;
+ }
+ FcMutexLock (lock);
+}
+
+static void
+unlock_config (void)
+{
+ FcMutexUnlock (_lock);
+}
+
+static void
+free_lock (void)
+{
+ FcMutex *lock;
+
+ lock = fc_atomic_ptr_get (&_lock);
+ if (lock && fc_atomic_ptr_cmpexch (&_lock, lock, NULL))
+ {
+ FcMutexFinish (lock);
+ free (lock);
+ }
+}
static FcConfig *
FcConfigEnsure (void)
@@ -44,8 +87,9 @@ retry:
{
config = FcInitLoadConfigAndFonts ();
- if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) {
- FcConfigDestroy (config);
+ if (!config || !fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) {
+ if (config)
+ FcConfigDestroy (config);
goto retry;
}
}
@@ -76,6 +120,7 @@ FcConfigFini (void)
FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig);
if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL))
FcConfigDestroy (cfg);
+ free_lock ();
}
static FcChar8 *
@@ -297,27 +342,31 @@ FcConfigReference (FcConfig *config)
{
if (!config)
{
- /* Do not use FcConfigGetCurrent () for the purpose of obtaining current FcConfig here.
- * because the reference counter must be increased before setting it to _fcConfig.
+ /* lock during obtaining the value from _fcConfig and count up refcount there,
+ * there are the race between them.
*/
+ lock_config ();
retry:
config = fc_atomic_ptr_get (&_fcConfig);
if (!config)
{
- config = FcConfigCreate ();
- FcRefInc (&config->ref);
+ unlock_config ();
- config = FcInitLoadOwnConfigAndFonts (config);
+ config = FcInitLoadConfigAndFonts ();
+ if (!config)
+ goto retry;
+ lock_config ();
if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config))
{
- FcConfigDestroy (config); /* To decrease the refcount for the above one. */
- FcConfigDestroy (config); /* To destroy it actualy */
+ FcConfigDestroy (config);
goto retry;
}
- return config;
}
+ FcRefInc (&config->ref);
+ unlock_config ();
}
- FcRefInc (&config->ref);
+ else
+ FcRefInc (&config->ref);
return config;
}
@@ -529,20 +578,29 @@ FcConfigSetCurrent (FcConfig *config)
{
FcConfig *cfg;
+ if (config)
+ {
+ if (!config->fonts[FcSetSystem])
+ if (!FcConfigBuildFonts (config))
+ return FcFalse;
+ FcRefInc (&config->ref);
+ }
+
+ lock_config ();
retry:
cfg = fc_atomic_ptr_get (&_fcConfig);
if (config == cfg)
+ {
+ unlock_config ();
+ if (config)
+ FcConfigDestroy (config);
return FcTrue;
-
- if (config && !config->fonts[FcSetSystem])
- if (!FcConfigBuildFonts (config))
- return FcFalse;
+ }
if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config))
goto retry;
-
- FcConfigReference (config);
+ unlock_config ();
if (cfg)
FcConfigDestroy (cfg);
@@ -2649,7 +2707,9 @@ FcConfigSetSysRoot (FcConfig *config,
{
FcChar8 *s = NULL;
FcBool init = FcFalse;
+ int nretry = 3;
+retry:
if (!config)
{
/* We can't use FcConfigGetCurrent() here to ensure
@@ -2681,6 +2741,17 @@ FcConfigSetSysRoot (FcConfig *config,
if (init)
{
config = FcInitLoadOwnConfigAndFonts (config);
+ if (!config)
+ {
+ /* Something failed. this is usually unlikely. so retrying */
+ init = FcFalse;
+ if (--nretry == 0)
+ {
+ fprintf (stderr, "Fontconfig warning: Unable to initialize config and retry limit exceeded. sysroot functionality may not work as expected.\n");
+ return;
+ }
+ goto retry;
+ }
FcConfigSetCurrent (config);
/* FcConfigSetCurrent() increases the refcount.
* decrease it here to avoid the memory leak.