Skip to content

Commit ebe76e2

Browse files
authored
Merge pull request #526 from rgacogne/fix-preload-hang-521
Fix: Better detection of recursive initialisation problems
2 parents aabe141 + c0aa618 commit ebe76e2

File tree

1 file changed

+56
-2
lines changed

1 file changed

+56
-2
lines changed

src/libfaketime.c

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ static bool check_missing_real(const char *name, bool missing)
341341
#define CHECK_MISSING_REAL(name) \
342342
check_missing_real(#name, (NULL == real_##name))
343343

344+
static pthread_mutex_t initialized_once_mutex;
344345
static pthread_once_t initialized_once_control = PTHREAD_ONCE_INIT;
345346

346347
/* prototypes */
@@ -715,12 +716,59 @@ static void ft_shm_destroy(void)
715716
}
716717
}
717718

719+
static void ft_initialize_errorcheck_mutex (pthread_mutex_t* mutex)
720+
{
721+
pthread_mutexattr_t attr;
722+
int ret = pthread_mutexattr_init(&attr);
723+
if (ret != 0) {
724+
fprintf(stderr, "libfaketime: failed to initialize mutex attribute: %d\n", ret);
725+
exit(-1);
726+
}
727+
ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
728+
if (ret != 0) {
729+
fprintf(stderr, "libfaketime: failed to set errorcheck mutex attribute: %d\n", ret);
730+
exit(-1);
731+
}
732+
ret = pthread_mutex_init(mutex, &attr);
733+
if (ret != 0) {
734+
fprintf(stderr, "libfaketime: failed to initialize errorcheck mutex: %d\n", ret);
735+
exit(-1);
736+
}
737+
}
738+
739+
static void ft_init_once_generic (bool* init_done, pthread_once_t* once_control, pthread_mutex_t* mutex, void (*init_mutex_cb)(void), void (*initializer_cb)(void))
740+
{
741+
pthread_once(once_control, init_mutex_cb);
742+
int ret = pthread_mutex_lock(mutex);
743+
if (ret == 0) {
744+
if (!*init_done) {
745+
// Set this to `true` before we call the initialisation; the effect is that
746+
// recursive calls to `ftpl_init` or `ft_shm_really_init` will be suppressed.
747+
// If anything that they use calls back to a time function
748+
// it will get some not- or partially-set-up faketime state.
749+
// We are betting that that's good enough.
750+
// (Empirically, on some platforms the shm functions call `statx`;
751+
// we think the timestamps in that call probably don't matter.)
752+
*init_done = true;
753+
initializer_cb();
754+
}
755+
pthread_mutex_unlock(mutex);
756+
}
757+
}
758+
759+
static pthread_mutex_t ft_shm_initialized_once_mutex;
718760
static pthread_once_t ft_shm_initialized_once_control = PTHREAD_ONCE_INIT;
719761

762+
static void ft_shm_init_mutex (void)
763+
{
764+
ft_initialize_errorcheck_mutex(&ft_shm_initialized_once_mutex);
765+
}
766+
720767
static void ft_shm_really_init (void);
721768
static void ft_shm_init (void)
722769
{
723-
pthread_once(&ft_shm_initialized_once_control, ft_shm_really_init);
770+
static bool init_done = false;
771+
ft_init_once_generic(&init_done, &ft_shm_initialized_once_control, &ft_shm_initialized_once_mutex, &ft_shm_init_mutex, &ft_shm_really_init);
724772
}
725773

726774
static void ft_shm_really_init (void)
@@ -3256,8 +3304,14 @@ static void ftpl_really_init(void)
32563304
dont_fake = dont_fake_final;
32573305
}
32583306

3307+
static void init_initialized_once_mutex (void)
3308+
{
3309+
ft_initialize_errorcheck_mutex(&initialized_once_mutex);
3310+
}
3311+
32593312
inline static void ftpl_init(void) {
3260-
pthread_once(&initialized_once_control, ftpl_really_init);
3313+
static bool init_done = false;
3314+
ft_init_once_generic(&init_done, &initialized_once_control, &initialized_once_mutex, &init_initialized_once_mutex, &ftpl_really_init);
32613315
}
32623316

32633317
void *ft_dlvsym(void *handle, const char *symbol, const char *version,

0 commit comments

Comments
 (0)