diff --git a/configure.ac b/configure.ac index 7bfc2a03ef..bebe4f22c8 100644 --- a/configure.ac +++ b/configure.ac @@ -3129,6 +3129,15 @@ AS_CASE(["$target_cpu-$target_os"], AS_IF([test "x$ac_cv_header_execinfo_h" = xyes], [ AC_CHECK_LIB([execinfo], [backtrace]) AC_CHECK_HEADERS([libunwind.h]) + + AC_CHECK_HEADERS([mach/task.h mach/mach_init.h mach/mach_port.h]) + AS_IF([ test \ + "x${ac_cv_header_mach_task_h}" = xyes -a \ + "x${ac_cv_header_mach_mach_init_h}" = xyes -a \ + "x${ac_cv_header_mach_mach_port_h}" = xyes \ + ], [ + AC_DEFINE([HAVE_MACH_TASK_EXCEPTION_PORTS], [1]) + ]) ])], [*-freebsd*|x86_64-netbsd*], [ AC_CHECK_HEADERS([execinfo.h]) diff --git a/gc.c b/gc.c index 0ccba2e433..0d6ad838fd 100644 --- a/gc.c +++ b/gc.c @@ -87,6 +87,11 @@ #include #endif +#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS +# include +# include +# include +#endif #undef LIST_HEAD /* ccan/list conflicts with BSD-origin sys/queue.h. */ #include "constant.h" @@ -5277,6 +5282,38 @@ install_handlers(void) static struct sigaction old_sigbus_handler; static struct sigaction old_sigsegv_handler; +#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS +static exception_mask_t old_exception_masks[32]; +static mach_port_t old_exception_ports[32]; +static exception_behavior_t old_exception_behaviors[32]; +static thread_state_flavor_t old_exception_flavors[32]; +static mach_msg_type_number_t old_exception_count; + +static void +disable_mach_bad_access_exc(void) +{ + old_exception_count = sizeof(old_exception_masks) / sizeof(old_exception_masks[0]); + task_swap_exception_ports( + mach_task_self(), EXC_MASK_BAD_ACCESS, + MACH_PORT_NULL, EXCEPTION_DEFAULT, 0, + old_exception_masks, &old_exception_count, + old_exception_ports, old_exception_behaviors, old_exception_flavors + ); +} + +static void +restore_mach_bad_access_exc(void) +{ + for (mach_msg_type_number_t i = 0; i < old_exception_count; i++) { + task_set_exception_ports( + mach_task_self(), + old_exception_masks[i], old_exception_ports[i], + old_exception_behaviors[i], old_exception_flavors[i] + ); + } +} +#endif + static void read_barrier_signal(int sig, siginfo_t * info, void * data) { @@ -5291,11 +5328,16 @@ read_barrier_signal(int sig, siginfo_t * info, void * data) sigaddset(&set, SIGBUS); sigaddset(&set, SIGSEGV); sigprocmask(SIG_UNBLOCK, &set, &prev_set); - +#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS + disable_mach_bad_access_exc(); +#endif // run handler read_barrier_handler((uintptr_t)info->si_addr); // reset SEGV/BUS handlers +#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS + restore_mach_bad_access_exc(); +#endif sigaction(SIGBUS, &prev_sigbus, NULL); sigaction(SIGSEGV, &prev_sigsegv, NULL); sigprocmask(SIG_SETMASK, &prev_set, NULL); @@ -5304,6 +5346,9 @@ read_barrier_signal(int sig, siginfo_t * info, void * data) static void uninstall_handlers(void) { +#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS + restore_mach_bad_access_exc(); +#endif sigaction(SIGBUS, &old_sigbus_handler, NULL); sigaction(SIGSEGV, &old_sigsegv_handler, NULL); } @@ -5319,6 +5364,9 @@ install_handlers(void) sigaction(SIGBUS, &action, &old_sigbus_handler); sigaction(SIGSEGV, &action, &old_sigsegv_handler); +#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS + disable_mach_bad_access_exc(); +#endif } #endif