From 5730dc0480a0d4160ff10dd2979b75c1bd203b10 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Thu, 26 Jul 2018 15:23:38 +0200 Subject: [PATCH 1/3] Ignore SEGV during profiler unwind on Unix. --- src/signals-unix.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/signals-unix.c b/src/signals-unix.c index 0fafe121cd9b6..439c49534cfd2 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -220,11 +220,19 @@ static int jl_is_on_sigstack(jl_ptls_t ptls, void *ptr, void *context) is_addr_on_sigstack(ptls, (void*)jl_get_rsp_from_ctx(context))); } +volatile static int profiler_state = 0; +static ucontext_t profiler_uc; + static void segv_handler(int sig, siginfo_t *info, void *context) { jl_ptls_t ptls = jl_get_ptls_states(); assert(sig == SIGSEGV || sig == SIGBUS); + if (profiler_state == 1) { + profiler_state = 2; + setcontext(&profiler_uc); + } + if (jl_addr_is_safepoint((uintptr_t)info->si_addr)) { #ifdef JULIA_ENABLE_THREADING jl_set_gc_and_wait(); @@ -667,9 +675,16 @@ static void *signal_listener(void *arg) // do backtrace for profiler if (profile && running) { if (bt_size_cur < bt_size_max - 1) { - // Get backtrace data - bt_size_cur += rec_backtrace_ctx((uintptr_t*)bt_data_prof + bt_size_cur, - bt_size_max - bt_size_cur - 1, signal_context); + profiler_state = 1; + getcontext(&profiler_uc); + if (profiler_state == 1) { + // Get backtrace data + bt_size_cur += rec_backtrace_ctx((uintptr_t*)bt_data_prof + bt_size_cur, + bt_size_max - bt_size_cur - 1, signal_context); + } else { + jl_safe_printf("WARNING: profiler attempt to access an invalid memory location\n"); + } + // Mark the end of this block with 0 bt_data_prof[bt_size_cur++] = 0; } From 24413c6fecc26f8e13de04223747e252e9b47120 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Thu, 26 Jul 2018 17:57:42 +0200 Subject: [PATCH 2/3] Alternative approach based on setjmp/longjmp with ptls->safe_restore. --- src/signals-unix.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/signals-unix.c b/src/signals-unix.c index 439c49534cfd2..bfb994950e26f 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -220,17 +220,21 @@ static int jl_is_on_sigstack(jl_ptls_t ptls, void *ptr, void *context) is_addr_on_sigstack(ptls, (void*)jl_get_rsp_from_ctx(context))); } -volatile static int profiler_state = 0; -static ucontext_t profiler_uc; - static void segv_handler(int sig, siginfo_t *info, void *context) { jl_ptls_t ptls = jl_get_ptls_states(); assert(sig == SIGSEGV || sig == SIGBUS); - if (profiler_state == 1) { - profiler_state = 2; - setcontext(&profiler_uc); + // if we're profiling, this segfault is likely caused by the unwinder. + // ignore the signal and jump back to where we came from. + if (running && ptls->safe_restore) { + // unblock the signal being handled + sigset_t sset; + sigemptyset(&sset); + sigaddset(&sset, sig); + sigprocmask(SIG_UNBLOCK, &sset, NULL); + + jl_longjmp(*ptls->safe_restore, 1); } if (jl_addr_is_safepoint((uintptr_t)info->si_addr)) { @@ -675,15 +679,21 @@ static void *signal_listener(void *arg) // do backtrace for profiler if (profile && running) { if (bt_size_cur < bt_size_max - 1) { - profiler_state = 1; - getcontext(&profiler_uc); - if (profiler_state == 1) { + // unwinding can fail, so keep track of the current state + // and restore from the SEGV handler if anything happens. + jl_ptls_t ptls = jl_get_ptls_states(); + jl_jmp_buf *old_buf = ptls->safe_restore; + jl_jmp_buf buf; + + ptls->safe_restore = &buf; + if (jl_setjmp(buf, 0)) { + jl_safe_printf("WARNING: profiler attempt to access an invalid memory location\n"); + } else { // Get backtrace data bt_size_cur += rec_backtrace_ctx((uintptr_t*)bt_data_prof + bt_size_cur, bt_size_max - bt_size_cur - 1, signal_context); - } else { - jl_safe_printf("WARNING: profiler attempt to access an invalid memory location\n"); } + ptls->safe_restore = old_buf; // Mark the end of this block with 0 bt_data_prof[bt_size_cur++] = 0; From a526b2993bf9494330a67519d66aee1820131ffe Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Fri, 27 Jul 2018 09:23:40 +0200 Subject: [PATCH 3/3] Reuse jl_call_in_ctx. --- src/signals-unix.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/signals-unix.c b/src/signals-unix.c index bfb994950e26f..230c0cb2dada5 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -89,6 +89,14 @@ static void jl_call_in_ctx(jl_ptls_t ptls, void (*fptr)(void), int sig, void *_c // checks that the syscall is made in the signal handler and that // the ucontext address is valid. Hopefully the value of the ucontext // will not be part of the validation... + if (!ptls->signal_stack) { + sigset_t sset; + sigemptyset(&sset); + sigaddset(&sset, sig); + sigprocmask(SIG_UNBLOCK, &sset, NULL); + fptr(); + return; + } uintptr_t rsp = (uintptr_t)ptls->signal_stack + sig_stack_size; assert(rsp % 16 == 0); #if defined(_OS_LINUX_) && defined(_CPU_X86_64_) @@ -225,18 +233,6 @@ static void segv_handler(int sig, siginfo_t *info, void *context) jl_ptls_t ptls = jl_get_ptls_states(); assert(sig == SIGSEGV || sig == SIGBUS); - // if we're profiling, this segfault is likely caused by the unwinder. - // ignore the signal and jump back to where we came from. - if (running && ptls->safe_restore) { - // unblock the signal being handled - sigset_t sset; - sigemptyset(&sset); - sigaddset(&sset, sig); - sigprocmask(SIG_UNBLOCK, &sset, NULL); - - jl_longjmp(*ptls->safe_restore, 1); - } - if (jl_addr_is_safepoint((uintptr_t)info->si_addr)) { #ifdef JULIA_ENABLE_THREADING jl_set_gc_and_wait();