--- old/src/cpu/ppc/vm/debug_ppc.cpp 2014-11-26 07:18:15.020081000 +0100 +++ new/src/cpu/ppc/vm/debug_ppc.cpp 2014-11-26 07:18:14.797063000 +0100 @@ -33,3 +33,10 @@ #include "utilities/top.hpp" void pd_ps(frame f) {} + + +#ifndef PRODUCT +// a sequence of bytes which, when used as opcodes, will cause a SIGILL +const uint8_t illegal_instruction_sequence[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +#endif + --- old/src/cpu/sparc/vm/debug_sparc.cpp 2014-11-26 07:18:17.042224000 +0100 +++ new/src/cpu/sparc/vm/debug_sparc.cpp 2014-11-26 07:18:16.838234000 +0100 @@ -81,4 +81,7 @@ tty->print("[%d] sp=" INTPTR_FORMAT " [bogus sp!]", count, p2i(sp)); } +// a sequence of bytes which, when used as opcodes, will cause a SIGILL +const uint8_t illegal_instruction_sequence[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + #endif // PRODUCT --- old/src/cpu/x86/vm/debug_x86.cpp 2014-11-26 07:18:19.028356000 +0100 +++ new/src/cpu/x86/vm/debug_x86.cpp 2014-11-26 07:18:18.250300000 +0100 @@ -32,3 +32,22 @@ #include "utilities/top.hpp" void pd_ps(frame f) {} + + +#ifndef PRODUCT +// a sequence of bytes which, when used as opcodes, will cause a SIGILL +const uint8_t illegal_instruction_sequence[8] = { + #if defined(AMD64) + // 06 => invalid instruction for x64 + 0x06 + #elif defined(IA32) + // Note: privileged instructions won't work, because they cause a SIGSEGV + // on Linux, not a SIGILL. "0f 0e" and "0f 0f" are invalid opcodes which + // will cause real SIGILL resp. EXCEPTION_ILLEGAL_INSTRUCTION. + 0x0f, 0x0f, + // Note: just in case this does not work, use a HLT which should be privilegued. + 0xF4 + #endif +}; +#endif + --- old/src/cpu/zero/vm/debug_zero.cpp 2014-11-26 07:18:22.388626000 +0100 +++ new/src/cpu/zero/vm/debug_zero.cpp 2014-11-26 07:18:22.185606000 +0100 @@ -35,3 +35,9 @@ void pd_ps(frame f) { ShouldNotCallThis(); } + +#ifndef PRODUCT +// a sequence of bytes which, when used as opcodes, will cause a SIGILL +const uint8_t illegal_instruction_sequence[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +#endif + --- old/src/os/aix/vm/vmError_aix.cpp 2014-11-26 07:18:24.891789000 +0100 +++ new/src/os/aix/vm/vmError_aix.cpp 2014-11-26 07:18:24.390771000 +0100 @@ -80,7 +80,6 @@ } int VMError::get_resetted_sigflags(int sig) { - // Handle all program errors. for (int i = 0; i < NUM_SIGNALS; i++) { if (SIGNALS[i] == sig) { return resettedSigflags[i]; @@ -90,7 +89,6 @@ } address VMError::get_resetted_sighandler(int sig) { - // Handle all program errors. for (int i = 0; i < NUM_SIGNALS; i++) { if (SIGNALS[i] == sig) { return resettedSighandler[i]; @@ -100,12 +98,19 @@ } static void crash_handler(int sig, siginfo_t* info, void* ucVoid) { + // Unmask current signal. sigset_t newset; sigemptyset(&newset); sigaddset(&newset, sig); + // and all other synchronous signals too. + for (int i = 0; i < NUM_SIGNALS; i++) { + sigaddset(&newset, SIGNALS[i]); + } + sigthreadmask(SIG_UNBLOCK, &newset, NULL); - Unimplemented(); + VMError err(NULL, sig, NULL, info, ucVoid); + err.report_and_die(); } void VMError::reset_signal_handlers() { --- old/src/os/bsd/vm/vmError_bsd.cpp 2014-11-26 07:18:29.132150000 +0100 +++ new/src/os/bsd/vm/vmError_bsd.cpp 2014-11-26 07:18:28.492083000 +0100 @@ -63,9 +63,21 @@ } while (yes); } +// handle all synchronous program error signals which may happen during error +// reporting. They must be unblocked, caught, handled. +// +// Note that in the hotspot signal handlers are installed with a fully filled +// signal mask, i.e. upon delivery all signals - also synchronous error signals +// - are blocked. For synchronous error signals this is deadly - program will +// hang or be ended immediately if secondary errors happend during error +// reporting. + +static const int SIGNALS[] = { SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP }; // add more if needed +static const int NUM_SIGNALS = sizeof(SIGNALS) / sizeof(int); + // Space for our "saved" signal flags and handlers -static int resettedSigflags[2]; -static address resettedSighandler[2]; +static int resettedSigflags[NUM_SIGNALS]; +static address resettedSighandler[NUM_SIGNALS]; static void save_signal(int idx, int sig) { @@ -78,19 +90,19 @@ } int VMError::get_resetted_sigflags(int sig) { - if(SIGSEGV == sig) { - return resettedSigflags[0]; - } else if(SIGBUS == sig) { - return resettedSigflags[1]; + for (int i = 0; i < NUM_SIGNALS; i++) { + if (SIGNALS[i] == sig) { + return resettedSigflags[i]; + } } return -1; } address VMError::get_resetted_sighandler(int sig) { - if(SIGSEGV == sig) { - return resettedSighandler[0]; - } else if(SIGBUS == sig) { - return resettedSighandler[1]; + for (int i = 0; i < NUM_SIGNALS; i++) { + if (SIGNALS[i] == sig) { + return resettedSighandler[i]; + } } return NULL; } @@ -100,16 +112,25 @@ sigset_t newset; sigemptyset(&newset); sigaddset(&newset, sig); - sigprocmask(SIG_UNBLOCK, &newset, NULL); + // also unmask other synchronous signals + for (int i = 0; i < NUM_SIGNALS; i++) { + sigaddset(&newset, SIGNALS[i]); + } + pthread_sigmask(SIG_UNBLOCK, &newset, NULL); VMError err(NULL, sig, NULL, info, ucVoid); err.report_and_die(); } void VMError::reset_signal_handlers() { - // Save sigflags for resetted signals - save_signal(0, SIGSEGV); - save_signal(1, SIGBUS); - os::signal(SIGSEGV, CAST_FROM_FN_PTR(void *, crash_handler)); - os::signal(SIGBUS, CAST_FROM_FN_PTR(void *, crash_handler)); + // install signal handlers for all synchronous program error signals + sigset_t newset; + sigemptyset(&newset); + + for (int i = 0; i < NUM_SIGNALS; i++) { + save_signal(i, SIGNALS[i]); + os::signal(SIGNALS[i], CAST_FROM_FN_PTR(void *, crash_handler)); + sigaddset(&newset, SIGNALS[i]); + } + pthread_sigmask(SIG_UNBLOCK, &newset, NULL); } --- old/src/os/linux/vm/vmError_linux.cpp 2014-11-26 07:18:32.134323000 +0100 +++ new/src/os/linux/vm/vmError_linux.cpp 2014-11-26 07:18:31.599290000 +0100 @@ -63,9 +63,21 @@ } while (yes); } +// handle all synchronous program error signals which may happen during error +// reporting. They must be unblocked, caught, handled. +// +// Note that in the hotspot signal handlers are installed with a fully filled +// signal mask, i.e. upon delivery all signals - also synchronous error signals +// - are blocked. For synchronous error signals this is deadly - program will +// hang or be ended immediately if secondary errors happend during error +// reporting. + +static const int SIGNALS[] = { SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP }; // add more if needed +static const int NUM_SIGNALS = sizeof(SIGNALS) / sizeof(int); + // Space for our "saved" signal flags and handlers -static int resettedSigflags[2]; -static address resettedSighandler[2]; +static int resettedSigflags[NUM_SIGNALS]; +static address resettedSighandler[NUM_SIGNALS]; static void save_signal(int idx, int sig) { @@ -78,19 +90,19 @@ } int VMError::get_resetted_sigflags(int sig) { - if(SIGSEGV == sig) { - return resettedSigflags[0]; - } else if(SIGBUS == sig) { - return resettedSigflags[1]; + for (int i = 0; i < NUM_SIGNALS; i++) { + if (SIGNALS[i] == sig) { + return resettedSigflags[i]; + } } return -1; } address VMError::get_resetted_sighandler(int sig) { - if(SIGSEGV == sig) { - return resettedSighandler[0]; - } else if(SIGBUS == sig) { - return resettedSighandler[1]; + for (int i = 0; i < NUM_SIGNALS; i++) { + if (SIGNALS[i] == sig) { + return resettedSighandler[i]; + } } return NULL; } @@ -100,16 +112,26 @@ sigset_t newset; sigemptyset(&newset); sigaddset(&newset, sig); - sigprocmask(SIG_UNBLOCK, &newset, NULL); + // also unmask other synchronous signals + for (int i = 0; i < NUM_SIGNALS; i++) { + sigaddset(&newset, SIGNALS[i]); + } + pthread_sigmask(SIG_UNBLOCK, &newset, NULL); VMError err(NULL, sig, NULL, info, ucVoid); err.report_and_die(); } void VMError::reset_signal_handlers() { - // Save sigflags for resetted signals - save_signal(0, SIGSEGV); - save_signal(1, SIGBUS); - os::signal(SIGSEGV, CAST_FROM_FN_PTR(void *, crash_handler)); - os::signal(SIGBUS, CAST_FROM_FN_PTR(void *, crash_handler)); + // install signal handlers for all synchronous program error signals + sigset_t newset; + sigemptyset(&newset); + + for (int i = 0; i < NUM_SIGNALS; i++) { + save_signal(i, SIGNALS[i]); + os::signal(SIGNALS[i], CAST_FROM_FN_PTR(void *, crash_handler)); + sigaddset(&newset, SIGNALS[i]); + } + pthread_sigmask(SIG_UNBLOCK, &newset, NULL); + } --- old/src/os/solaris/vm/vmError_solaris.cpp 2014-11-26 07:18:36.722662000 +0100 +++ new/src/os/solaris/vm/vmError_solaris.cpp 2014-11-26 07:18:36.022637000 +0100 @@ -30,6 +30,7 @@ #include #include +#include #include void VMError::show_message_box(char *buf, int buflen) { @@ -59,9 +60,21 @@ } while (yes); } +// handle all synchronous program error signals which may happen during error +// reporting. They must be unblocked, caught, handled. +// +// Note that in the hotspot signal handlers are installed with a fully filled +// signal mask, i.e. upon delivery all signals - also synchronous error signals +// - are blocked. For synchronous error signals this is deadly - program will +// hang or be ended immediately if secondary errors happend during error +// reporting. + +static const int SIGNALS[] = { SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP }; // add more if needed +static const int NUM_SIGNALS = sizeof(SIGNALS) / sizeof(int); + // Space for our "saved" signal flags and handlers -static int resettedSigflags[2]; -static address resettedSighandler[2]; +static int resettedSigflags[NUM_SIGNALS]; +static address resettedSighandler[NUM_SIGNALS]; static void save_signal(int idx, int sig) { @@ -74,19 +87,19 @@ } int VMError::get_resetted_sigflags(int sig) { - if(SIGSEGV == sig) { - return resettedSigflags[0]; - } else if(SIGBUS == sig) { - return resettedSigflags[1]; + for (int i = 0; i < NUM_SIGNALS; i++) { + if (SIGNALS[i] == sig) { + return resettedSigflags[i]; + } } return -1; } address VMError::get_resetted_sighandler(int sig) { - if(SIGSEGV == sig) { - return resettedSighandler[0]; - } else if(SIGBUS == sig) { - return resettedSighandler[1]; + for (int i = 0; i < NUM_SIGNALS; i++) { + if (SIGNALS[i] == sig) { + return resettedSighandler[i]; + } } return NULL; } @@ -96,16 +109,25 @@ sigset_t newset; sigemptyset(&newset); sigaddset(&newset, sig); - sigprocmask(SIG_UNBLOCK, &newset, NULL); + // also unmask other synchronous signals + for (int i = 0; i < NUM_SIGNALS; i++) { + sigaddset(&newset, SIGNALS[i]); + } + thr_sigsetmask(SIG_UNBLOCK, &newset, NULL); VMError err(NULL, sig, NULL, info, ucVoid); err.report_and_die(); } void VMError::reset_signal_handlers() { - // Save sigflags for resetted signals - save_signal(0, SIGSEGV); - save_signal(1, SIGBUS); - os::signal(SIGSEGV, CAST_FROM_FN_PTR(void *, crash_handler)); - os::signal(SIGBUS, CAST_FROM_FN_PTR(void *, crash_handler)); + // install signal handlers for all synchronous program error signals + sigset_t newset; + sigemptyset(&newset); + + for (int i = 0; i < NUM_SIGNALS; i++) { + save_signal(i, SIGNALS[i]); + os::signal(SIGNALS[i], CAST_FROM_FN_PTR(void *, crash_handler)); + sigaddset(&newset, SIGNALS[i]); + } + thr_sigsetmask(SIG_UNBLOCK, &newset, NULL); } --- old/src/share/vm/runtime/globals.hpp 2014-11-26 07:18:40.103915000 +0100 +++ new/src/share/vm/runtime/globals.hpp 2014-11-26 07:18:39.583987000 +0100 @@ -900,6 +900,10 @@ "determines which error to provoke. See test_error_handler() " \ "in debug.cpp.") \ \ + notproduct(uintx, TestCrashInErrorHandler, 0, \ + "If > 0, provokes an error inside VM error handler (a secondary " \ + "crash). see test_error_handler() in debug.cpp.") \ + \ develop(bool, Verbose, false, \ "Print additional debugging information from other modes") \ \ --- old/src/share/vm/utilities/debug.cpp 2014-11-26 07:18:43.119159000 +0100 +++ new/src/share/vm/utilities/debug.cpp 2014-11-26 07:18:42.750128000 +0100 @@ -308,13 +308,80 @@ #ifndef PRODUCT #include +typedef void (*voidfun_t)(); +// Crash with an authentic sigill at a known PC. +static void crash_with_sigill() { + bool rc = false; + const size_t size = os::vm_page_size(); + static void* pc = NULL; + if (!pc) { + void* p = os::reserve_memory(size, NULL, 0); + if (p) { + bool rc = os::commit_memory((char*)p, size, true); + if (rc) { + memset(p, 0, size); + memcpy(p, illegal_instruction_sequence, + sizeof(illegal_instruction_sequence)); + pc = p; + } + } + } + + guarantee(pc, "failed to initialized sigill test blob"); + + tty->print_cr("will jump to PC " PTR_FORMAT + ", which should cause a SIGILL.", pc); + tty->flush(); + + volatile voidfun_t g_voidfun = NULL; + +#if defined(IA64) || defined(PPC64) + // on ia64 and on ppc we have function descriptors. + struct { void* p1; void* p2; } fundes = + { pc, pc }; + void* p = (void*)(&fundes); + g_voidfun = (voidfun_t) (p); +#else + g_voidfun = (voidfun_t)pc; +#endif + + g_voidfun(); // boom. + +} // end: crash_with_sigill + +// crash with sigsegv at non-null address. +static void crash_with_segfault() { + + char* const crash_addr = (char*) get_segfault_address(); + + tty->print_cr("will access address " PTR_FORMAT + ", which should cause a SIGSEGV.", crash_addr); + tty->flush(); + + *crash_addr = 'X'; + +} // end: crash_with_segfault + +// returns an address which is guaranteed to generate a SIGSEGV on read, +// for test purposes, which is not NULL and contains bits in every word +void* get_segfault_address() { + return (void*) +#ifdef _LP64 + 0xABC0000000000ABCULL; +#else + 0x00000ABC; +#endif +} + void test_error_handler() { - uintx test_num = ErrorHandlerTest; - if (test_num == 0) return; + controlled_crash(ErrorHandlerTest); +} + +void controlled_crash(int how) { + if (how == 0) return; // If asserts are disabled, use the corresponding guarantee instead. - size_t n = test_num; - NOT_DEBUG(if (n <= 2) n += 2); + NOT_DEBUG(if (how <= 2) how += 2); const char* const str = "hello"; const size_t num = (size_t)os::vm_page_size(); @@ -325,7 +392,7 @@ const void (*funcPtr)(void) = (const void(*)()) 0xF; // bad function pointer // Keep this in sync with test/runtime/6888954/vmerrors.sh. - switch (n) { + switch (how) { case 1: assert(str == NULL, "expected null"); case 2: assert(num == 1023 && *str == 'X', err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str)); @@ -350,8 +417,10 @@ // There's no guarantee the bad function pointer will crash us // so "break" out to the ShouldNotReachHere(). case 13: (*funcPtr)(); break; + case 14: crash_with_segfault(); break; + case 15: crash_with_sigill(); break; - default: tty->print_cr("ERROR: %d: unexpected test_num value.", n); + default: tty->print_cr("ERROR: %d: unexpected test_num value.", how); } ShouldNotReachHere(); } --- old/src/share/vm/utilities/debug.hpp 2014-11-26 07:18:44.847254000 +0100 +++ new/src/share/vm/utilities/debug.hpp 2014-11-26 07:18:44.664240000 +0100 @@ -261,6 +261,28 @@ /* Test assert(), fatal(), guarantee(), etc. */ NOT_PRODUCT(void test_error_handler();) +// crash in a controlled way: +// how can be one of: +// 1,2 - asserts +// 3,4 - guarantee +// 5-7 - fatal +// 8 - vm_exit_out_of_memory +// 9 - ShouldNotCallThis +// 10 - ShouldNotReachHere +// 11 - Unimplemented +// 12,13 - (not guaranteed) crashes +// 14 - SIGSEGV +// 15 - SIGILL +NOT_PRODUCT(void controlled_crash(int how);) + +// returns an address which is guaranteed to generate a SIGSEGV on read, +// for test purposes, which is not NULL and contains bits in every word +NOT_PRODUCT(void* get_segfault_address();) + + +// a sequence of bytes which, when used as opcodes, will cause a SIGILL +NOT_PRODUCT(extern const uint8_t illegal_instruction_sequence[8]); + void pd_ps(frame f); void pd_obfuscate_location(char *buf, size_t buflen); --- old/src/share/vm/utilities/vmError.cpp 2014-11-26 07:18:46.528390000 +0100 +++ new/src/share/vm/utilities/vmError.cpp 2014-11-26 07:18:46.246361000 +0100 @@ -352,6 +352,22 @@ "Runtime Environment to continue."); } +#ifndef PRODUCT + // Error handler self tests + + // test secondary error handling. Test it twice, to test that resetting + // error handler after a secondary crash works. + STEP(13, "(test secondary crash 1)") + if (TestCrashInErrorHandler != 0) { + controlled_crash(TestCrashInErrorHandler); + } + + STEP(14, "(test secondary crash 2)") + if (TestCrashInErrorHandler != 0) { + controlled_crash(TestCrashInErrorHandler); + } +#endif // PRODUCT + STEP(15, "(printing type of error)") switch(_id) { @@ -785,6 +801,15 @@ st->cr(); } +#ifdef PRODUCT + // print a defined marker to show that error handling finished correctly. + STEP(290, "(printing end marker)" ) + + if (_verbose) { + st->print_cr("END."); + } +#endif + END # undef BEGIN