Fix potential race condition in FcConfigSetCurrent and FcConfigReference
This commit is contained in:
parent
b5bcf61fe7
commit
aa8c8cfa9f
|
@ -1085,6 +1085,8 @@ FcDirCacheLoadFile (const FcChar8 *cache_file, struct stat *file_stat)
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
config = FcConfigReference (NULL);
|
config = FcConfigReference (NULL);
|
||||||
|
if (!config)
|
||||||
|
return NULL;
|
||||||
cache = FcDirCacheMapFd (config, fd, file_stat, NULL);
|
cache = FcDirCacheMapFd (config, fd, file_stat, NULL);
|
||||||
FcConfigDestroy (config);
|
FcConfigDestroy (config);
|
||||||
close (fd);
|
close (fd);
|
||||||
|
|
101
src/fccfg.c
101
src/fccfg.c
|
@ -33,6 +33,49 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static FcConfig *_fcConfig; /* MT-safe */
|
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 *
|
static FcConfig *
|
||||||
FcConfigEnsure (void)
|
FcConfigEnsure (void)
|
||||||
|
@ -44,7 +87,8 @@ retry:
|
||||||
{
|
{
|
||||||
config = FcInitLoadConfigAndFonts ();
|
config = FcInitLoadConfigAndFonts ();
|
||||||
|
|
||||||
if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) {
|
if (!config || !fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) {
|
||||||
|
if (config)
|
||||||
FcConfigDestroy (config);
|
FcConfigDestroy (config);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
@ -76,6 +120,7 @@ FcConfigFini (void)
|
||||||
FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig);
|
FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig);
|
||||||
if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL))
|
if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL))
|
||||||
FcConfigDestroy (cfg);
|
FcConfigDestroy (cfg);
|
||||||
|
free_lock ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static FcChar8 *
|
static FcChar8 *
|
||||||
|
@ -297,26 +342,30 @@ FcConfigReference (FcConfig *config)
|
||||||
{
|
{
|
||||||
if (!config)
|
if (!config)
|
||||||
{
|
{
|
||||||
/* Do not use FcConfigGetCurrent () for the purpose of obtaining current FcConfig here.
|
/* lock during obtaining the value from _fcConfig and count up refcount there,
|
||||||
* because the reference counter must be increased before setting it to _fcConfig.
|
* there are the race between them.
|
||||||
*/
|
*/
|
||||||
|
lock_config ();
|
||||||
retry:
|
retry:
|
||||||
config = fc_atomic_ptr_get (&_fcConfig);
|
config = fc_atomic_ptr_get (&_fcConfig);
|
||||||
if (!config)
|
if (!config)
|
||||||
{
|
{
|
||||||
config = FcConfigCreate ();
|
unlock_config ();
|
||||||
FcRefInc (&config->ref);
|
|
||||||
|
|
||||||
config = FcInitLoadOwnConfigAndFonts (config);
|
config = FcInitLoadConfigAndFonts ();
|
||||||
|
if (!config)
|
||||||
|
goto retry;
|
||||||
|
lock_config ();
|
||||||
if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config))
|
if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config))
|
||||||
{
|
{
|
||||||
FcConfigDestroy (config); /* To decrease the refcount for the above one. */
|
FcConfigDestroy (config);
|
||||||
FcConfigDestroy (config); /* To destroy it actualy */
|
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
return config;
|
|
||||||
}
|
}
|
||||||
|
FcRefInc (&config->ref);
|
||||||
|
unlock_config ();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
FcRefInc (&config->ref);
|
FcRefInc (&config->ref);
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
|
@ -529,20 +578,29 @@ FcConfigSetCurrent (FcConfig *config)
|
||||||
{
|
{
|
||||||
FcConfig *cfg;
|
FcConfig *cfg;
|
||||||
|
|
||||||
|
if (config)
|
||||||
|
{
|
||||||
|
if (!config->fonts[FcSetSystem])
|
||||||
|
if (!FcConfigBuildFonts (config))
|
||||||
|
return FcFalse;
|
||||||
|
FcRefInc (&config->ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
lock_config ();
|
||||||
retry:
|
retry:
|
||||||
cfg = fc_atomic_ptr_get (&_fcConfig);
|
cfg = fc_atomic_ptr_get (&_fcConfig);
|
||||||
|
|
||||||
if (config == cfg)
|
if (config == cfg)
|
||||||
|
{
|
||||||
|
unlock_config ();
|
||||||
|
if (config)
|
||||||
|
FcConfigDestroy (config);
|
||||||
return FcTrue;
|
return FcTrue;
|
||||||
|
}
|
||||||
if (config && !config->fonts[FcSetSystem])
|
|
||||||
if (!FcConfigBuildFonts (config))
|
|
||||||
return FcFalse;
|
|
||||||
|
|
||||||
if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config))
|
if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config))
|
||||||
goto retry;
|
goto retry;
|
||||||
|
unlock_config ();
|
||||||
FcConfigReference (config);
|
|
||||||
if (cfg)
|
if (cfg)
|
||||||
FcConfigDestroy (cfg);
|
FcConfigDestroy (cfg);
|
||||||
|
|
||||||
|
@ -2649,7 +2707,9 @@ FcConfigSetSysRoot (FcConfig *config,
|
||||||
{
|
{
|
||||||
FcChar8 *s = NULL;
|
FcChar8 *s = NULL;
|
||||||
FcBool init = FcFalse;
|
FcBool init = FcFalse;
|
||||||
|
int nretry = 3;
|
||||||
|
|
||||||
|
retry:
|
||||||
if (!config)
|
if (!config)
|
||||||
{
|
{
|
||||||
/* We can't use FcConfigGetCurrent() here to ensure
|
/* We can't use FcConfigGetCurrent() here to ensure
|
||||||
|
@ -2681,6 +2741,17 @@ FcConfigSetSysRoot (FcConfig *config,
|
||||||
if (init)
|
if (init)
|
||||||
{
|
{
|
||||||
config = FcInitLoadOwnConfigAndFonts (config);
|
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 (config);
|
||||||
/* FcConfigSetCurrent() increases the refcount.
|
/* FcConfigSetCurrent() increases the refcount.
|
||||||
* decrease it here to avoid the memory leak.
|
* decrease it here to avoid the memory leak.
|
||||||
|
|
Loading…
Reference in New Issue