summaryrefslogtreecommitdiff
path: root/signal.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-10-16 08:15:46 (GMT)
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-10-16 08:15:46 (GMT)
commit0d88cd9394ecbcef0c733f7973504d6ff49db228 (patch)
tree50414072536eccf84282baded5fb47b622934d27 /signal.c
parent5c3c2ddda2f410a25985f0e0fe7092d8c21a3657 (diff)
signal.c: abort if nesting reserved signal
* signal.c (check_reserved_signal): abort if reserved signal received in reserved signal handlers. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47977 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'signal.c')
-rw-r--r--signal.c48
1 files changed, 39 insertions, 9 deletions
diff --git a/signal.c b/signal.c
index d3c7cb8..fd7ee1b 100644
--- a/signal.c
+++ b/signal.c
@@ -799,10 +799,14 @@ check_stack_overflow(const void *addr)
#define MESSAGE_FAULT_ADDRESS
#endif
+#if defined SIGSEGV || defined SIGBUS || defined SIGILL || defined SIGFPE
+static void check_reserved_signal(const char *name);
+
#ifdef SIGBUS
static RETSIGTYPE
sigbus(int sig SIGINFO_ARG)
{
+ check_reserved_signal("BUS");
/*
* Mac OS X makes KERN_PROTECTION_FAILURE when thread touch guard page.
* and it's delivered as SIGBUS instead of SIGSEGV to userland. It's crazy
@@ -815,7 +819,6 @@ sigbus(int sig SIGINFO_ARG)
}
#endif
-#ifdef SIGSEGV
static void
ruby_abort(void)
{
@@ -830,25 +833,49 @@ ruby_abort(void)
}
-static int segv_received = 0;
extern int ruby_disable_gc;
+#ifdef SIGSEGV
static RETSIGTYPE
sigsegv(int sig SIGINFO_ARG)
{
- if (segv_received) {
+ check_reserved_signal("SEGV");
+ CHECK_STACK_OVERFLOW();
+ rb_bug_context(SIGINFO_CTX, "Segmentation fault" MESSAGE_FAULT_ADDRESS);
+}
+#endif
+
+#ifdef SIGILL
+static RETSIGTYPE
+sigill(int sig SIGINFO_ARG)
+{
+ check_reserved_signal("ILL");
+#if defined __APPLE__
+ CHECK_STACK_OVERFLOW();
+#endif
+ rb_bug_context(SIGINFO_CTX, "Illegal instruction" MESSAGE_FAULT_ADDRESS);
+}
+#endif
+
+static void
+check_reserved_signal(const char *name)
+{
+ static const char *received;
+ const char *prev = ATOMIC_PTR_EXCHANGE(received, name);
+
+ if (prev) {
ssize_t RB_UNUSED_VAR(err);
- static const char msg[] = "SEGV received in SEGV handler\n";
+ static const char msg1[] = " received in ";
+ static const char msg2[] = " handler\n";
- err = write(2, msg, sizeof(msg));
+ err = write(2, name, strlen(name));
+ err = write(2, msg1, sizeof(msg1));
+ err = write(2, prev, strlen(prev));
+ err = write(2, msg2, sizeof(msg2));
ruby_abort();
}
- CHECK_STACK_OVERFLOW();
-
- segv_received = 1;
ruby_disable_gc = 1;
- rb_bug_context(SIGINFO_CTX, "Segmentation fault" MESSAGE_FAULT_ADDRESS);
}
#endif
@@ -1381,6 +1408,9 @@ Init_signal(void)
#ifdef SIGBUS
install_sighandler(SIGBUS, (sighandler_t)sigbus);
#endif
+#ifdef SIGILL
+ install_sighandler(SIGILL, (sighandler_t)sigill);
+#endif
#ifdef SIGSEGV
# ifdef USE_SIGALTSTACK
rb_register_sigaltstack(GET_THREAD());