Skip to content

Commit cbec2ae

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 87f99fb commit cbec2ae

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

@@ -568,16 +571,23 @@ static int jl_lock_profile_mach(int dlsymlock)
568571
// workaround for old keymgr bugs
569572
void *unused = NULL;
570573
int keymgr_locked = _keymgr_get_and_lock_processwide_ptr_2(KEYMGR_GCC3_DW2_OBJ_LIST, &unused) == 0;
571-
// workaround for new dlsym4 bugs (API and bugs introduced in macOS 12.1)
574+
// workaround for new dlsym4 bugs in the workaround for dlsym bugs: _dyld_atfork_prepare
575+
// acquires its locks in the wrong order, but fortunately we happen to able to guard it
576+
// with this call to force it to prevent that TSAN violation from causing a deadlock
577+
if (dlsymlock && _dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL)
578+
_dyld_dlopen_atfork_prepare();
579+
// workaround for new dlsym4 bugs (API and bugs introduced circa macOS 12.1)
572580
if (dlsymlock && _dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
573581
_dyld_atfork_prepare();
574582
return keymgr_locked;
575583
}
576584

577585
static void jl_unlock_profile_mach(int dlsymlock, int keymgr_locked)
578586
{
579-
if (dlsymlock && _dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) \
580-
_dyld_atfork_parent(); \
587+
if (dlsymlock && _dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
588+
_dyld_atfork_parent();
589+
if (dlsymlock && _dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL)
590+
_dyld_dlopen_atfork_parent();
581591
if (keymgr_locked)
582592
_keymgr_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
583593
jl_unlock_profile();
@@ -622,14 +632,19 @@ void *mach_profile_listener(void *arg)
622632
break;
623633
}
624634

635+
if (_dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL)
636+
_dyld_dlopen_atfork_prepare();
625637
if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
626638
_dyld_atfork_prepare(); // briefly acquire the dlsym lock
627639
host_thread_state_t state;
628640
int valid_thread = jl_thread_suspend_and_get_state2(i, &state);
629641
unw_context_t *uc = (unw_context_t*)&state;
630642
if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
631643
_dyld_atfork_parent(); // quickly release the dlsym lock
632-
644+
if (_dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL)
645+
_dyld_dlopen_atfork_parent();
646+
if (!valid_thread)
647+
continue;
633648
if (running) {
634649
#ifdef LLVMLIBUNWIND
635650
/*

0 commit comments

Comments
 (0)