Skip to content

Commit

Permalink
signal.c: save the original sighandlers for fatal signals
Browse files Browse the repository at this point in the history
On Android, a signal handler that is not SIG_DFL is set by default for
SIGSEGV.  Ruby's install_sighandler inserts Ruby's handler only when the
signal has no handler, so it does not insert Ruby's SEGV report handler,
which caused some test failures.

This changeset forces to install Ruby's handler for some fatal signals
(sigbus, sigsegv, and sigill).  They keep the original handlers, and
call them when the interpreter receives the signals.
  • Loading branch information
mame committed Oct 9, 2019
1 parent dd477df commit 891cbd6
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 13 deletions.
4 changes: 3 additions & 1 deletion error.c
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ rb_bug(const char *fmt, ...)
}

void
rb_bug_for_fatal_signal(const void *ctx, const char *fmt, ...)
rb_bug_for_fatal_signal(RETSIGTYPE (*default_sighandler)(int), int sig, const void *ctx, const char *fmt, ...)
{
const char *file = NULL;
int line = 0;
Expand All @@ -610,6 +610,8 @@ rb_bug_for_fatal_signal(const void *ctx, const char *fmt, ...)

report_bug(file, line, fmt, ctx);

if (default_sighandler) default_sighandler(sig);

die();
}

Expand Down
32 changes: 21 additions & 11 deletions signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,7 @@ NOINLINE(static void check_reserved_signal_(const char *name, size_t name_len));

#ifdef SIGBUS

static sighandler_t default_sigbus_handler;
NORETURN(static ruby_sigaction_t sigbus);

static RETSIGTYPE
Expand All @@ -933,25 +934,27 @@ sigbus(int sig SIGINFO_ARG)
#if defined __APPLE__ || defined __linux__
CHECK_STACK_OVERFLOW();
#endif
rb_bug_for_fatal_signal(SIGINFO_CTX, "Bus Error" MESSAGE_FAULT_ADDRESS);
rb_bug_for_fatal_signal(default_sigbus_handler, sig, SIGINFO_CTX, "Bus Error" MESSAGE_FAULT_ADDRESS);
}
#endif

#ifdef SIGSEGV

static sighandler_t default_sigsegv_handler;
NORETURN(static ruby_sigaction_t sigsegv);

static RETSIGTYPE
sigsegv(int sig SIGINFO_ARG)
{
check_reserved_signal("SEGV");
CHECK_STACK_OVERFLOW();
rb_bug_for_fatal_signal(SIGINFO_CTX, "Segmentation fault" MESSAGE_FAULT_ADDRESS);
rb_bug_for_fatal_signal(default_sigsegv_handler, sig, SIGINFO_CTX, "Segmentation fault" MESSAGE_FAULT_ADDRESS);
}
#endif

#ifdef SIGILL

static sighandler_t default_sigill_handler;
NORETURN(static ruby_sigaction_t sigill);

static RETSIGTYPE
Expand All @@ -961,7 +964,7 @@ sigill(int sig SIGINFO_ARG)
#if defined __APPLE__
CHECK_STACK_OVERFLOW();
#endif
rb_bug_for_fatal_signal(SIGINFO_CTX, "Illegal instruction" MESSAGE_FAULT_ADDRESS);
rb_bug_for_fatal_signal(default_sigill_handler, sig, SIGINFO_CTX, "Illegal instruction" MESSAGE_FAULT_ADDRESS);
}
#endif

Expand Down Expand Up @@ -1432,21 +1435,28 @@ sig_list(VALUE _)
perror(failed); \
} while (0)
static int
install_sighandler(int signum, sighandler_t handler)
install_sighandler_core(int signum, sighandler_t handler, sighandler_t *old_handler)
{
sighandler_t old;

old = ruby_signal(signum, handler);
if (old == SIG_ERR) return -1;
/* signal handler should be inherited during exec. */
if (old != SIG_DFL) {
ruby_signal(signum, old);
if (old_handler) {
*old_handler = (old == SIG_DFL || old == SIG_IGN) ? 0 : old;
}
else {
/* signal handler should be inherited during exec. */
if (old != SIG_DFL) {
ruby_signal(signum, old);
}
}
return 0;
}

# define install_sighandler(signum, handler) \
INSTALL_SIGHANDLER(install_sighandler(signum, handler), #signum, signum)
INSTALL_SIGHANDLER(install_sighandler_core(signum, handler, NULL), #signum, signum)
# define force_install_sighandler(signum, handler, old_handler) \
INSTALL_SIGHANDLER(install_sighandler_core(signum, handler, old_handler), #signum, signum)

#if RUBY_SIGCHLD
static int
Expand Down Expand Up @@ -1558,14 +1568,14 @@ Init_signal(void)

if (!ruby_enable_coredump) {
#ifdef SIGBUS
install_sighandler(SIGBUS, (sighandler_t)sigbus);
force_install_sighandler(SIGBUS, (sighandler_t)sigbus, &default_sigbus_handler);
#endif
#ifdef SIGILL
install_sighandler(SIGILL, (sighandler_t)sigill);
force_install_sighandler(SIGILL, (sighandler_t)sigill, &default_sigill_handler);
#endif
#ifdef SIGSEGV
RB_ALTSTACK_INIT(GET_VM()->main_altstack);
install_sighandler(SIGSEGV, (sighandler_t)sigsegv);
force_install_sighandler(SIGSEGV, (sighandler_t)sigsegv, &default_sigsegv_handler);
#endif
}
#ifdef SIGPIPE
Expand Down
2 changes: 1 addition & 1 deletion vm_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -1624,7 +1624,7 @@ extern void rb_vmdebug_debug_print_post(const rb_execution_context_t *ec, const
#define SDR() rb_vmdebug_stack_dump_raw(GET_EC(), GET_EC()->cfp)
#define SDR2(cfp) rb_vmdebug_stack_dump_raw(GET_EC(), (cfp))
void rb_vm_bugreport(const void *);
NORETURN(void rb_bug_for_fatal_signal(const void *, const char *fmt, ...));
NORETURN(void rb_bug_for_fatal_signal(RETSIGTYPE (*default_sighandler)(int), int sig, const void *, const char *fmt, ...));

/* functions about thread/vm execution */
RUBY_SYMBOL_EXPORT_BEGIN
Expand Down

0 comments on commit 891cbd6

Please sign in to comment.