From 213458b7b0479c14adc4b0c256a657923ae7be11 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Sat, 29 Apr 2023 20:21:26 -0300 Subject: [PATCH 1/3] Fix dyld lock not getting unlocked on invalid threads. (#49446) --- src/signals-mach.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/signals-mach.c b/src/signals-mach.c index dbd303d868e8e..dee1bb393ee98 100644 --- a/src/signals-mach.c +++ b/src/signals-mach.c @@ -621,8 +621,7 @@ void *mach_profile_listener(void *arg) if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) _dyld_atfork_prepare(); // briefly acquire the dlsym lock host_thread_state_t state; - if (!jl_thread_suspend_and_get_state2(i, &state)) - continue; + int valid_thread = jl_thread_suspend_and_get_state2(i, &state); unw_context_t *uc = (unw_context_t*)&state; if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) _dyld_atfork_parent(); // quickly release the dlsym lock From f7d20c6a165547ede5ae512801d25ee19263a125 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 11 May 2023 13:29:07 -0400 Subject: [PATCH 2/3] macOS: avoid deadlock inside dyld4 deadlock workaround (#49740) Extend the fix for #43578 (2939272af2ef3fe9d8921f7ed0a6500e31a550c9) to cover the deadlock bug present internally in dyld4 inside the function we use to avoid the previous deadlock issue. Fix #49733 --- src/signals-mach.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/signals-mach.c b/src/signals-mach.c index dee1bb393ee98..a0941d1b59f97 100644 --- a/src/signals-mach.c +++ b/src/signals-mach.c @@ -36,6 +36,9 @@ extern int _keymgr_set_lockmode_processwide_ptr(unsigned int key, unsigned int m extern void _dyld_atfork_prepare(void) __attribute__((weak_import)); extern void _dyld_atfork_parent(void) __attribute__((weak_import)); //extern void _dyld_fork_child(void) __attribute__((weak_import)); +extern void _dyld_dlopen_atfork_prepare(void) __attribute__((weak_import)); +extern void _dyld_dlopen_atfork_parent(void) __attribute__((weak_import)); +//extern void _dyld_dlopen_atfork_child(void) __attribute__((weak_import)); static void attach_exception_port(thread_port_t thread, int segv_only); @@ -564,7 +567,12 @@ static int jl_lock_profile_mach(int dlsymlock) // workaround for old keymgr bugs void *unused = NULL; int keymgr_locked = _keymgr_get_and_lock_processwide_ptr_2(KEYMGR_GCC3_DW2_OBJ_LIST, &unused) == 0; - // workaround for new dlsym4 bugs (API and bugs introduced in macOS 12.1) + // workaround for new dlsym4 bugs in the workaround for dlsym bugs: _dyld_atfork_prepare + // acquires its locks in the wrong order, but fortunately we happen to able to guard it + // with this call to force it to prevent that TSAN violation from causing a deadlock + if (dlsymlock && _dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL) + _dyld_dlopen_atfork_prepare(); + // workaround for new dlsym4 bugs (API and bugs introduced circa macOS 12.1) if (dlsymlock && _dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) _dyld_atfork_prepare(); return keymgr_locked; @@ -572,8 +580,10 @@ static int jl_lock_profile_mach(int dlsymlock) static void jl_unlock_profile_mach(int dlsymlock, int keymgr_locked) { - if (dlsymlock && _dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) \ - _dyld_atfork_parent(); \ + if (dlsymlock && _dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) + _dyld_atfork_parent(); + if (dlsymlock && _dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL) + _dyld_dlopen_atfork_parent(); if (keymgr_locked) _keymgr_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST); jl_unlock_profile(); @@ -618,6 +628,8 @@ void *mach_profile_listener(void *arg) break; } + if (_dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL) + _dyld_dlopen_atfork_prepare(); if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) _dyld_atfork_prepare(); // briefly acquire the dlsym lock host_thread_state_t state; @@ -625,7 +637,10 @@ void *mach_profile_listener(void *arg) unw_context_t *uc = (unw_context_t*)&state; if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) _dyld_atfork_parent(); // quickly release the dlsym lock - + if (_dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL) + _dyld_dlopen_atfork_parent(); + if (!valid_thread) + continue; if (running) { #ifdef LLVMLIBUNWIND /* From 007bcef42a2d0fc194376eca50814371cb5e71ae Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 12 May 2023 10:02:12 -0400 Subject: [PATCH 3/3] fix build failure with dyld4 deadlock workaround (#49776) Accidentally missed in #49740 Fixes #49773 --- src/mach_dyld_atfork.tbd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mach_dyld_atfork.tbd b/src/mach_dyld_atfork.tbd index 9a5d18099dbcf..c2cda4417ec38 100644 --- a/src/mach_dyld_atfork.tbd +++ b/src/mach_dyld_atfork.tbd @@ -21,5 +21,6 @@ install-name: '/usr/lib/libSystem.B.dylib' exports: - targets: [ arm64-macos, arm64e-macos, x86_64-macos, x86_64-maccatalyst, arm64-maccatalyst, arm64e-maccatalyst ] - symbols: [ __dyld_atfork_parent, __dyld_atfork_prepare ] + symbols: [ __dyld_atfork_parent, __dyld_atfork_prepare, + __dyld_dlopen_atfork_parent, __dyld_dlopen_atfork_prepare ] ...