aboutsummaryrefslogtreecommitdiffstats
path: root/gc.c
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2020-11-30 05:07:28 +0900
committerKoichi Sasada <ko1@atdot.net>2020-11-30 05:10:48 +0900
commit77936ad679d63a6d0e7b585db4c31db5507f5586 (patch)
tree69b378c6155c066175d88bebdd1f2f132b130de2 /gc.c
parent02c32b2e9299726e20bb4499fa7c1f5430ce0b6d (diff)
downloadruby-77936ad679d63a6d0e7b585db4c31db5507f5586.tar.gz
support SIGSEGV/BUS while read_barrier_handler()
read_barrier_handler() can cause SIGSEGV/BUS so it should show the errors.
Diffstat (limited to 'gc.c')
-rw-r--r--gc.c29
1 files changed, 18 insertions, 11 deletions
diff --git a/gc.c b/gc.c
index 7fe4f8c609..ab3f8610ce 100644
--- a/gc.c
+++ b/gc.c
@@ -4597,18 +4597,25 @@ static struct sigaction old_sigsegv_handler;
static void
read_barrier_signal(int sig, siginfo_t * info, void * data)
{
- extern int ruby_on_ci;
- if (ruby_on_ci) { // `read_barrier_handler` may crash. Report backtraces first on CI.
-# if HAVE_BACKTRACE // `rb_bug_without_die` may crash on `control_frame_dump`. Report a C backtrace first.
- fprintf(stderr, "-- C level backtrace (read_barrier_signal) "
- "-------------------------------------------\n");
- rb_print_backtrace();
- fprintf(stderr, "\n");
-# endif
- extern void rb_bug_without_die(const char *fmt, ...);
- rb_bug_without_die("died with read_barrier_signal installed");
- }
+ // setup SEGV/BUS handlers for errors
+ struct sigaction prev_sigbus, prev_sigsegv;
+ sigaction(SIGBUS, &old_sigbus_handler, &prev_sigbus);
+ sigaction(SIGSEGV, &old_sigsegv_handler, &prev_sigsegv);
+
+ // enable SIGBUS/SEGV
+ sigset_t set, prev_set;
+ sigemptyset(&set);
+ sigaddset(&set, SIGBUS);
+ sigaddset(&set, SIGSEGV);
+ sigprocmask(SIG_UNBLOCK, &set, &prev_set);
+
+ // run handler
read_barrier_handler((intptr_t)info->si_addr);
+
+ // reset SEGV/BUS handlers
+ sigaction(SIGBUS, &prev_sigbus, NULL);
+ sigaction(SIGSEGV, &prev_sigsegv, NULL);
+ sigprocmask(SIG_SETMASK, &prev_set, NULL);
}
static void uninstall_handlers(void)