Skip to content

Commit e207952

Browse files
vtjnashkpamnany
authored andcommitted
macOS: avoid deadlock inside dyld4 deadlock workaround (JuliaLang#49740)
Extend the fix for JuliaLang#43578 (2939272) to cover the deadlock bug present internally in dyld4 inside the function we use to avoid the previous deadlock issue. Fix JuliaLang#49733
1 parent 3f99734 commit e207952

File tree

1 file changed

+19
-4
lines changed

1 file changed

+19
-4
lines changed

src/signals-mach.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ extern int _keymgr_set_lockmode_processwide_ptr(unsigned int key, unsigned int m
3636
extern void _dyld_atfork_prepare(void) __attribute__((weak_import));
3737
extern void _dyld_atfork_parent(void) __attribute__((weak_import));
3838
//extern void _dyld_fork_child(void) __attribute__((weak_import));
39+
extern void _dyld_dlopen_atfork_prepare(void) __attribute__((weak_import));
40+
extern void _dyld_dlopen_atfork_parent(void) __attribute__((weak_import));
41+
//extern void _dyld_dlopen_atfork_child(void) __attribute__((weak_import));
3942

4043
static void attach_exception_port(thread_port_t thread, int segv_only);
4144

@@ -564,16 +567,23 @@ static int jl_lock_profile_mach(int dlsymlock)
564567
// workaround for old keymgr bugs
565568
void *unused = NULL;
566569
int keymgr_locked = _keymgr_get_and_lock_processwide_ptr_2(KEYMGR_GCC3_DW2_OBJ_LIST, &unused) == 0;
567-
// workaround for new dlsym4 bugs (API and bugs introduced in macOS 12.1)
570+
// workaround for new dlsym4 bugs in the workaround for dlsym bugs: _dyld_atfork_prepare
571+
// acquires its locks in the wrong order, but fortunately we happen to able to guard it
572+
// with this call to force it to prevent that TSAN violation from causing a deadlock
573+
if (dlsymlock && _dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL)
574+
_dyld_dlopen_atfork_prepare();
575+
// workaround for new dlsym4 bugs (API and bugs introduced circa macOS 12.1)
568576
if (dlsymlock && _dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
569577
_dyld_atfork_prepare();
570578
return keymgr_locked;
571579
}
572580

573581
static void jl_unlock_profile_mach(int dlsymlock, int keymgr_locked)
574582
{
575-
if (dlsymlock && _dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) \
576-
_dyld_atfork_parent(); \
583+
if (dlsymlock && _dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
584+
_dyld_atfork_parent();
585+
if (dlsymlock && _dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL)
586+
_dyld_dlopen_atfork_parent();
577587
if (keymgr_locked)
578588
_keymgr_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
579589
jl_unlock_profile();
@@ -618,6 +628,8 @@ void *mach_profile_listener(void *arg)
618628
break;
619629
}
620630

631+
if (_dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL)
632+
_dyld_dlopen_atfork_prepare();
621633
if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
622634
_dyld_atfork_prepare(); // briefly acquire the dlsym lock
623635
host_thread_state_t state;
@@ -626,7 +638,10 @@ void *mach_profile_listener(void *arg)
626638
unw_context_t *uc = (unw_context_t*)&state;
627639
if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
628640
_dyld_atfork_parent(); // quickly release the dlsym lock
629-
641+
if (_dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL)
642+
_dyld_dlopen_atfork_parent();
643+
if (!valid_thread)
644+
continue;
630645
if (running) {
631646
#ifdef LLVMLIBUNWIND
632647
/*

0 commit comments

Comments
 (0)