Skip to content

Commit 528949f

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

File tree

1 file changed

+17
-3
lines changed

1 file changed

+17
-3
lines changed

src/signals-mach.c

Lines changed: 17 additions & 3 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();
@@ -611,13 +621,17 @@ void *mach_profile_listener(void *arg)
611621
break;
612622
}
613623

624+
if (_dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL)
625+
_dyld_dlopen_atfork_prepare();
614626
if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
615627
_dyld_atfork_prepare(); // briefly acquire the dlsym lock
616628
host_thread_state_t state;
617629
int valid_thread = jl_thread_suspend_and_get_state2(i, &state);
618630
unw_context_t *uc = (unw_context_t*)&state;
619631
if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
620632
_dyld_atfork_parent(); // quickly release the dlsym lock
633+
if (_dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL)
634+
_dyld_dlopen_atfork_parent();
621635
if (!valid_thread)
622636
continue;
623637
if (running) {

0 commit comments

Comments
 (0)