8255711: Fix and unify hotspot signal handlers

Reviewed-by: coleenp, gziemski, dholmes
This commit is contained in:
Thomas Stuefe 2020-11-09 12:03:06 +00:00
parent d99e1f6c29
commit dd8e4ffbe5
15 changed files with 270 additions and 853 deletions

View file

@ -21,7 +21,7 @@
# questions. # questions.
# #
JVM_handle_linux_signal JVM_handle_aix_signal
numa_error numa_error
numa_warn numa_warn
sysThreadAvailableStackWithSlack sysThreadAvailableStackWithSlack

View file

@ -26,6 +26,7 @@
#include "jvm.h" #include "jvm.h"
#include "logging/log.hpp" #include "logging/log.hpp"
#include "runtime/atomic.hpp"
#include "runtime/globals.hpp" #include "runtime/globals.hpp"
#include "runtime/interfaceSupport.inline.hpp" #include "runtime/interfaceSupport.inline.hpp"
#include "runtime/os.hpp" #include "runtime/os.hpp"
@ -71,10 +72,6 @@ extern "C" {
static sigset_t check_signal_done; static sigset_t check_signal_done;
static bool check_signals = true; static bool check_signals = true;
// This boolean allows users to forward their own non-matching signals
// to JVM_handle_bsd_signal/JVM_handle_linux_signal, harmlessly.
static bool signal_handlers_are_installed = false;
debug_only(static bool signal_sets_initialized = false); debug_only(static bool signal_sets_initialized = false);
static sigset_t unblocked_sigs, vm_sigs, preinstalled_sigs; static sigset_t unblocked_sigs, vm_sigs, preinstalled_sigs;
struct sigaction sigact[NSIG]; struct sigaction sigact[NSIG];
@ -261,6 +258,8 @@ static const struct {
{ -1, NULL } { -1, NULL }
}; };
static const char* get_signal_name(int sig, char* out, size_t outlen);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// sun.misc.Signal support // sun.misc.Signal support
@ -313,6 +312,8 @@ static int check_pending_signals() {
} }
} while (threadIsSuspended); } while (threadIsSuspended);
} }
ShouldNotReachHere();
return 0; // Satisfy compiler
} }
int os::signal_wait() { int os::signal_wait() {
@ -408,50 +409,6 @@ bool PosixSignals::chained_handler(int sig, siginfo_t* siginfo, void* context) {
return chained; return chained;
} }
////////////////////////////////////////////////////////////////////////////////
// signal handling (except suspend/resume)
// This routine may be used by user applications as a "hook" to catch signals.
// The user-defined signal handler must pass unrecognized signals to this
// routine, and if it returns true (non-zero), then the signal handler must
// return immediately. If the flag "abort_if_unrecognized" is true, then this
// routine will never retun false (zero), but instead will execute a VM panic
// routine kill the process.
//
// If this routine returns false, it is OK to call it again. This allows
// the user-defined signal handler to perform checks either before or after
// the VM performs its own checks. Naturally, the user code would be making
// a serious error if it tried to handle an exception (such as a null check
// or breakpoint) that the VM was generating for its own correct operation.
//
// This routine may recognize any of the following kinds of signals:
// SIGBUS, SIGSEGV, SIGILL, SIGFPE, SIGQUIT, SIGPIPE, SIGXFSZ, SIGUSR1.
// It should be consulted by handlers for any of those signals.
//
// The caller of this routine must pass in the three arguments supplied
// to the function referred to in the "sa_sigaction" (not the "sa_handler")
// field of the structure passed to sigaction(). This routine assumes that
// the sa_flags field passed to sigaction() includes SA_SIGINFO and SA_RESTART.
//
// Note that the VM will print warnings if it detects conflicting signal
// handlers, unless invoked with the option "-XX:+AllowUserSignalHandlers".
//
#if defined(BSD)
extern "C" JNIEXPORT int JVM_handle_bsd_signal(int signo, siginfo_t* siginfo,
void* ucontext,
int abort_if_unrecognized);
#elif defined(AIX)
extern "C" JNIEXPORT int JVM_handle_aix_signal(int signo, siginfo_t* siginfo,
void* ucontext,
int abort_if_unrecognized);
#else
extern "C" JNIEXPORT int JVM_handle_linux_signal(int signo, siginfo_t* siginfo,
void* ucontext,
int abort_if_unrecognized);
#endif
///// Synchronous (non-deferrable) error signals (ILL, SEGV, FPE, BUS, TRAP): ///// Synchronous (non-deferrable) error signals (ILL, SEGV, FPE, BUS, TRAP):
// These signals are special because they cannot be deferred and, if they // These signals are special because they cannot be deferred and, if they
@ -502,21 +459,151 @@ void PosixSignals::unblock_error_signals() {
::pthread_sigmask(SIG_UNBLOCK, &set, NULL); ::pthread_sigmask(SIG_UNBLOCK, &set, NULL);
} }
// Renamed from 'signalHandler' to avoid collision with other shared libs. class ErrnoPreserver: public StackObj {
static void javaSignalHandler(int sig, siginfo_t* info, void* uc) { const int _saved;
assert(info != NULL && uc != NULL, "it must be old kernel"); public:
ErrnoPreserver() : _saved(errno) {}
~ErrnoPreserver() { errno = _saved; }
};
////////////////////////////////////////////////////////////////////////////////
// JVM_handle_(linux|aix|bsd)_signal()
// This routine is the shared part of the central hotspot signal handler. It can
// also be called by a user application, if a user application prefers to do
// signal handling itself - in that case it needs to pass signals the VM
// internally uses on to the VM first.
//
// The user-defined signal handler must pass unrecognized signals to this
// routine, and if it returns true (non-zero), then the signal handler must
// return immediately. If the flag "abort_if_unrecognized" is true, then this
// routine will never return false (zero), but instead will execute a VM panic
// routine to kill the process.
//
// If this routine returns false, it is OK to call it again. This allows
// the user-defined signal handler to perform checks either before or after
// the VM performs its own checks. Naturally, the user code would be making
// a serious error if it tried to handle an exception (such as a null check
// or breakpoint) that the VM was generating for its own correct operation.
//
// This routine may recognize any of the following kinds of signals:
// SIGBUS, SIGSEGV, SIGILL, SIGFPE, SIGQUIT, SIGPIPE, SIGXFSZ, SIGUSR1.
// It should be consulted by handlers for any of those signals.
//
// The caller of this routine must pass in the three arguments supplied
// to the function referred to in the "sa_sigaction" (not the "sa_handler")
// field of the structure passed to sigaction(). This routine assumes that
// the sa_flags field passed to sigaction() includes SA_SIGINFO and SA_RESTART.
//
// Note that the VM will print warnings if it detects conflicting signal
// handlers, unless invoked with the option "-XX:+AllowUserSignalHandlers".
//
#if defined(BSD)
#define JVM_HANDLE_XXX_SIGNAL JVM_handle_bsd_signal
#elif defined(AIX)
#define JVM_HANDLE_XXX_SIGNAL JVM_handle_aix_signal
#elif defined(LINUX)
#define JVM_HANDLE_XXX_SIGNAL JVM_handle_linux_signal
#else
#error who are you?
#endif
extern "C" JNIEXPORT
int JVM_HANDLE_XXX_SIGNAL(int sig, siginfo_t* info,
void* ucVoid, int abort_if_unrecognized)
{
assert(info != NULL && ucVoid != NULL, "sanity");
// Note: it's not uncommon that JNI code uses signal/sigset to install,
// then restore certain signal handler (e.g. to temporarily block SIGPIPE,
// or have a SIGILL handler when detecting CPU type). When that happens,
// this handler might be invoked with junk info/ucVoid. To avoid unnecessary
// crash when libjsig is not preloaded, try handle signals that do not require
// siginfo/ucontext first.
// Preserve errno value over signal handler.
// (note: RAII ok here, even with JFR thread crash protection, see below).
ErrnoPreserver ep;
// Unblock all synchronous error signals (see JDK-8252533)
PosixSignals::unblock_error_signals(); PosixSignals::unblock_error_signals();
int orig_errno = errno; // Preserve errno value over signal handler. ucontext_t* const uc = (ucontext_t*) ucVoid;
#if defined(BSD) Thread* const t = Thread::current_or_null_safe();
JVM_handle_bsd_signal(sig, info, uc, true);
#elif defined(AIX) // Handle JFR thread crash protection.
JVM_handle_aix_signal(sig, info, uc, true); // Note: this may cause us to longjmp away. Do not use any code before this
#else // point which really needs any form of epilogue code running, eg RAII objects.
JVM_handle_linux_signal(sig, info, uc, true); os::ThreadCrashProtection::check_crash_protection(sig, t);
bool signal_was_handled = false;
// Handle assertion poison page accesses.
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
signal_was_handled = handle_assert_poison_fault(ucVoid, info->si_addr);
}
#endif #endif
errno = orig_errno;
// Ignore SIGPIPE and SIGXFSZ (4229104, 6499219).
if (sig == SIGPIPE || sig == SIGXFSZ) {
PosixSignals::chained_handler(sig, info, ucVoid);
signal_was_handled = true; // unconditionally.
}
// Call platform dependent signal handler.
if (!signal_was_handled) {
JavaThread* const jt = (t != NULL && t->is_Java_thread()) ? (JavaThread*) t : NULL;
signal_was_handled = PosixSignals::pd_hotspot_signal_handler(sig, info, uc, jt);
}
// From here on, if the signal had not been handled, it is a fatal error.
// Give the chained signal handler - should it exist - a shot.
if (!signal_was_handled) {
signal_was_handled = PosixSignals::chained_handler(sig, info, ucVoid);
}
// Invoke fatal error handling.
if (!signal_was_handled && abort_if_unrecognized) {
// Extract pc from context for the error handler to display.
address pc = NULL;
if (uc != NULL) {
// prepare fault pc address for error reporting.
if (S390_ONLY(sig == SIGILL || sig == SIGFPE) NOT_S390(false)) {
pc = (address)info->si_addr;
} else {
pc = PosixSignals::ucontext_get_pc(uc);
}
}
#if defined(ZERO) && !defined(PRODUCT)
char buf[64];
VMError::report_and_die(t, sig, pc, info, ucVoid,
"\n#"
"\n# /--------------------\\"
"\n# | %-7s |"
"\n# \\---\\ /--------------/"
"\n# /"
"\n# [-] |\\_/| "
"\n# (+)=C |o o|__ "
"\n# | | =-*-=__\\ "
"\n# OOO c_c_(___)",
get_signal_name(sig, buf, sizeof(buf)));
#else
VMError::report_and_die(t, sig, pc, info, ucVoid);
#endif
// VMError should not return.
ShouldNotReachHere();
}
return signal_was_handled;
}
// Entry point for the hotspot signal handler.
static void javaSignalHandler(int sig, siginfo_t* info, void* ucVoid) {
// Do not add any code here!
// Only add code to either JVM_HANDLE_XXX_SIGNAL or PosixSignals::pd_hotspot_signal_handler.
(void)JVM_HANDLE_XXX_SIGNAL(sig, info, ucVoid, true);
} }
static void UserHandler(int sig, void *siginfo, void *context) { static void UserHandler(int sig, void *siginfo, void *context) {
@ -766,9 +853,7 @@ void os::run_periodic_checks() {
do_signal_check(SIGBUS); do_signal_check(SIGBUS);
do_signal_check(SIGPIPE); do_signal_check(SIGPIPE);
do_signal_check(SIGXFSZ); do_signal_check(SIGXFSZ);
#if defined(PPC64) PPC64_ONLY(do_signal_check(SIGTRAP);)
do_signal_check(SIGTRAP);
#endif
// ReduceSignalUsage allows the user to override these handlers // ReduceSignalUsage allows the user to override these handlers
// see comments at the very top and jvm_md.h // see comments at the very top and jvm_md.h
@ -935,7 +1020,6 @@ static bool is_valid_signal(int sig) {
#endif #endif
} }
// Returned string is a constant. For unknown signals "UNKNOWN" is returned.
static const char* get_signal_name(int sig, char* out, size_t outlen) { static const char* get_signal_name(int sig, char* out, size_t outlen) {
const char* ret = NULL; const char* ret = NULL;
@ -1075,7 +1159,7 @@ int os::get_signal_number(const char* signal_name) {
return -1; return -1;
} }
void set_signal_handler(int sig, bool set_installed) { void set_signal_handler(int sig) {
// Check for overwrite. // Check for overwrite.
struct sigaction oldAct; struct sigaction oldAct;
sigaction(sig, (struct sigaction*)NULL, &oldAct); sigaction(sig, (struct sigaction*)NULL, &oldAct);
@ -1086,7 +1170,7 @@ void set_signal_handler(int sig, bool set_installed) {
if (oldhand != CAST_FROM_FN_PTR(void*, SIG_DFL) && if (oldhand != CAST_FROM_FN_PTR(void*, SIG_DFL) &&
oldhand != CAST_FROM_FN_PTR(void*, SIG_IGN) && oldhand != CAST_FROM_FN_PTR(void*, SIG_IGN) &&
oldhand != CAST_FROM_FN_PTR(void*, (sa_sigaction_t)javaSignalHandler)) { oldhand != CAST_FROM_FN_PTR(void*, (sa_sigaction_t)javaSignalHandler)) {
if (AllowUserSignalHandlers || !set_installed) { if (AllowUserSignalHandlers) {
// Do not overwrite; user takes responsibility to forward to us. // Do not overwrite; user takes responsibility to forward to us.
return; return;
} else if (UseSignalChaining) { } else if (UseSignalChaining) {
@ -1103,13 +1187,8 @@ void set_signal_handler(int sig, bool set_installed) {
struct sigaction sigAct; struct sigaction sigAct;
sigfillset(&(sigAct.sa_mask)); sigfillset(&(sigAct.sa_mask));
remove_error_signals_from_set(&(sigAct.sa_mask)); remove_error_signals_from_set(&(sigAct.sa_mask));
sigAct.sa_handler = SIG_DFL;
if (!set_installed) {
sigAct.sa_flags = SA_SIGINFO|SA_RESTART;
} else {
sigAct.sa_sigaction = javaSignalHandler; sigAct.sa_sigaction = javaSignalHandler;
sigAct.sa_flags = SA_SIGINFO|SA_RESTART; sigAct.sa_flags = SA_SIGINFO|SA_RESTART;
}
#if defined(__APPLE__) #if defined(__APPLE__)
// Needed for main thread as XNU (Mac OS X kernel) will only deliver SIGSEGV // Needed for main thread as XNU (Mac OS X kernel) will only deliver SIGSEGV
// (which starts as SIGBUS) on main thread with faulting address inside "stack+guard pages" // (which starts as SIGBUS) on main thread with faulting address inside "stack+guard pages"
@ -1136,18 +1215,9 @@ void set_signal_handler(int sig, bool set_installed) {
assert(oldhand2 == oldhand, "no concurrent signal handler installation"); assert(oldhand2 == oldhand, "no concurrent signal handler installation");
} }
// install signal handlers for signals that HotSpot needs to
// handle in order to support Java-level exception handling.
bool PosixSignals::are_signal_handlers_installed() {
return signal_handlers_are_installed;
}
// install signal handlers for signals that HotSpot needs to // install signal handlers for signals that HotSpot needs to
// handle in order to support Java-level exception handling. // handle in order to support Java-level exception handling.
void PosixSignals::install_signal_handlers() { void PosixSignals::install_signal_handlers() {
if (!signal_handlers_are_installed) {
signal_handlers_are_installed = true;
// signal-chaining // signal-chaining
typedef void (*signal_setting_t)(); typedef void (*signal_setting_t)();
@ -1168,15 +1238,13 @@ void PosixSignals::install_signal_handlers() {
(*begin_signal_setting)(); (*begin_signal_setting)();
} }
set_signal_handler(SIGSEGV, true); set_signal_handler(SIGSEGV);
set_signal_handler(SIGPIPE, true); set_signal_handler(SIGPIPE);
set_signal_handler(SIGBUS, true); set_signal_handler(SIGBUS);
set_signal_handler(SIGILL, true); set_signal_handler(SIGILL);
set_signal_handler(SIGFPE, true); set_signal_handler(SIGFPE);
#if defined(PPC64) || defined(AIX) PPC64_ONLY(set_signal_handler(SIGTRAP);)
set_signal_handler(SIGTRAP, true); set_signal_handler(SIGXFSZ);
#endif
set_signal_handler(SIGXFSZ, true);
#if defined(__APPLE__) #if defined(__APPLE__)
// In Mac OS X 10.4, CrashReporter will write a crash log for all 'fatal' signals, including // In Mac OS X 10.4, CrashReporter will write a crash log for all 'fatal' signals, including
@ -1218,7 +1286,6 @@ void PosixSignals::install_signal_handlers() {
check_signals = false; check_signals = false;
} }
} }
}
} }
// Returns one-line short description of a signal set in a user provided buffer. // Returns one-line short description of a signal set in a user provided buffer.
@ -1354,9 +1421,7 @@ void PosixSignals::signal_sets_init() {
sigaddset(&unblocked_sigs, SIGSEGV); sigaddset(&unblocked_sigs, SIGSEGV);
sigaddset(&unblocked_sigs, SIGBUS); sigaddset(&unblocked_sigs, SIGBUS);
sigaddset(&unblocked_sigs, SIGFPE); sigaddset(&unblocked_sigs, SIGFPE);
#if defined(PPC64) || defined(AIX) PPC64_ONLY(sigaddset(&unblocked_sigs, SIGTRAP);)
sigaddset(&unblocked_sigs, SIGTRAP);
#endif
sigaddset(&unblocked_sigs, SR_signum); sigaddset(&unblocked_sigs, SR_signum);
if (!ReduceSignalUsage) { if (!ReduceSignalUsage) {

View file

@ -38,7 +38,11 @@ class PosixSignals : public AllStatic {
public: public:
static bool are_signal_handlers_installed(); // The platform dependent parts of the central hotspot signal handler.
// Returns true if the signal had been recognized and handled, false if not. If true, caller should
// return from signal handling.
static bool pd_hotspot_signal_handler(int sig, siginfo_t* info, ucontext_t* uc, JavaThread* thread);
static void install_signal_handlers(); static void install_signal_handlers();
static bool is_sig_ignored(int sig); static bool is_sig_ignored(int sig);

View file

@ -2144,6 +2144,8 @@ static int check_pending_signals() {
} }
} while (threadIsSuspended); } while (threadIsSuspended);
} }
ShouldNotReachHere();
return 0; // Satisfy compiler
} }
int os::signal_wait() { int os::signal_wait() {

View file

@ -168,43 +168,8 @@ frame os::current_frame() {
return os::get_sender_for_C_frame(&tmp); return os::get_sender_for_C_frame(&tmp);
} }
// Utility functions bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
ucontext_t* uc, JavaThread* thread) {
extern "C" JNIEXPORT int
JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrecognized) {
ucontext_t* uc = (ucontext_t*) ucVoid;
Thread* t = Thread::current_or_null_safe();
// Note: it's not uncommon that JNI code uses signal/sigset to install
// then restore certain signal handler (e.g. to temporarily block SIGPIPE,
// or have a SIGILL handler when detecting CPU type). When that happens,
// JVM_handle_aix_signal() might be invoked with junk info/ucVoid. To
// avoid unnecessary crash when libjsig is not preloaded, try handle signals
// that do not require siginfo/ucontext first.
if (sig == SIGPIPE || sig == SIGXFSZ) {
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return 1;
} else {
// Ignoring SIGPIPE - see bugs 4229104
return 1;
}
}
JavaThread* thread = NULL;
VMThread* vmthread = NULL;
if (PosixSignals::are_signal_handlers_installed()) {
if (t != NULL) {
if(t->is_Java_thread()) {
thread = t->as_Java_thread();
}
else if(t->is_VM_thread()) {
vmthread = (VMThread *)t;
}
}
}
// Decide if this trap can be handled by a stub. // Decide if this trap can be handled by a stub.
address stub = NULL; address stub = NULL;
@ -226,8 +191,8 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
} }
} }
if (info == NULL || uc == NULL || thread == NULL && vmthread == NULL) { if (info == NULL || uc == NULL) {
goto run_chained_handler; return false; // Fatal error
} }
// If we are a java thread... // If we are a java thread...
@ -237,11 +202,11 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
if (sig == SIGSEGV && thread->is_in_full_stack(addr)) { if (sig == SIGSEGV && thread->is_in_full_stack(addr)) {
// stack overflow // stack overflow
if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) {
return 1; // continue return true; // continue
} else if (stub != NULL) { } else if (stub != NULL) {
goto run_stub; goto run_stub;
} else { } else {
goto report_and_die; return false; // Fatal error
} }
} // end handle SIGSEGV inside stack boundaries } // end handle SIGSEGV inside stack boundaries
@ -281,17 +246,6 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
// happens rarely. In heap based and disjoint base compressd oop modes also loads // happens rarely. In heap based and disjoint base compressd oop modes also loads
// are used for null checks. // are used for null checks.
// A VM-related SIGILL may only occur if we are not in the zero page.
// On AIX, we get a SIGILL if we jump to 0x0 or to somewhere else
// in the zero page, because it is filled with 0x0. We ignore
// explicit SIGILLs in the zero page.
if (sig == SIGILL && (pc < (address) 0x200)) {
if (TraceTraps) {
tty->print_raw_cr("SIGILL happened inside zero page.");
}
goto report_and_die;
}
int stop_type = -1; int stop_type = -1;
// Handle signal from NativeJump::patch_verified_entry(). // Handle signal from NativeJump::patch_verified_entry().
if (sig == SIGILL && nativeInstruction_at(pc)->is_sigill_zombie_not_entrant()) { if (sig == SIGILL && nativeInstruction_at(pc)->is_sigill_zombie_not_entrant()) {
@ -384,10 +338,7 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
tty->print_cr("trap: %s: %s (SIGTRAP, stop type %d)", msg, detail_msg, stop_type); tty->print_cr("trap: %s: %s (SIGTRAP, stop type %d)", msg, detail_msg, stop_type);
} }
va_list detail_args; return false; // Fatal error
VMError::report_and_die(INTERNAL_ERROR, msg, detail_msg, detail_args, thread,
pc, info, ucVoid, NULL, 0, 0);
va_end(detail_args);
} }
else if (sig == SIGBUS) { else if (sig == SIGBUS) {
@ -403,7 +354,7 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
} }
next_pc = SharedRuntime::handle_unsafe_access(thread, next_pc); next_pc = SharedRuntime::handle_unsafe_access(thread, next_pc);
os::Aix::ucontext_set_pc(uc, next_pc); os::Aix::ucontext_set_pc(uc, next_pc);
return 1; return true;
} }
} }
} }
@ -428,7 +379,7 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
} }
next_pc = SharedRuntime::handle_unsafe_access(thread, next_pc); next_pc = SharedRuntime::handle_unsafe_access(thread, next_pc);
os::Aix::ucontext_set_pc(uc, next_pc); os::Aix::ucontext_set_pc(uc, next_pc);
return 1; return true;
} }
} }
@ -450,32 +401,10 @@ run_stub:
// Save all thread context in case we need to restore it. // Save all thread context in case we need to restore it.
if (thread != NULL) thread->set_saved_exception_pc(pc); if (thread != NULL) thread->set_saved_exception_pc(pc);
os::Aix::ucontext_set_pc(uc, stub); os::Aix::ucontext_set_pc(uc, stub);
return 1; return true;
} }
run_chained_handler: return false; // Fatal error
// signal-chaining
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return 1;
}
if (!abort_if_unrecognized) {
// caller wants another chance, so give it to him
return 0;
}
report_and_die:
// Use sigthreadmask instead of sigprocmask on AIX and unmask current signal.
sigset_t newset;
sigemptyset(&newset);
sigaddset(&newset, sig);
sigthreadmask(SIG_UNBLOCK, &newset, NULL);
VMError::report_and_die(t, sig, pc, info, ucVoid);
ShouldNotReachHere();
return 0;
} }
void os::Aix::init_thread_fpu_state(void) { void os::Aix::init_thread_fpu_state(void) {

View file

@ -385,56 +385,14 @@ frame os::current_frame() {
} }
} }
// Utility functions
// From IA32 System Programming Guide // From IA32 System Programming Guide
enum { enum {
trap_page_fault = 0xE trap_page_fault = 0xE
}; };
extern "C" JNIEXPORT int bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
JVM_handle_bsd_signal(int sig, ucontext_t* uc, JavaThread* thread) {
siginfo_t* info,
void* ucVoid,
int abort_if_unrecognized) {
ucontext_t* uc = (ucontext_t*) ucVoid;
Thread* t = Thread::current_or_null_safe();
// If crash protection is installed we may longjmp away and no destructors
// for objects in this scope will be run.
// So don't use any RAII utilities before crash protection is checked.
os::ThreadCrashProtection::check_crash_protection(sig, t);
// Note: it's not uncommon that JNI code uses signal/sigset to install
// then restore certain signal handler (e.g. to temporarily block SIGPIPE,
// or have a SIGILL handler when detecting CPU type). When that happens,
// JVM_handle_bsd_signal() might be invoked with junk info/ucVoid. To
// avoid unnecessary crash when libjsig is not preloaded, try handle signals
// that do not require siginfo/ucontext first.
if (sig == SIGPIPE || sig == SIGXFSZ) {
// allow chained handler to go first
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return true;
} else {
// Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219
return true;
}
}
JavaThread* thread = NULL;
VMThread* vmthread = NULL;
if (PosixSignals::are_signal_handlers_installed()) {
if (t != NULL ){
if(t->is_Java_thread()) {
thread = t->as_Java_thread();
}
else if(t->is_VM_thread()){
vmthread = (VMThread *)t;
}
}
}
/* /*
NOTE: does not seem to work on bsd. NOTE: does not seem to work on bsd.
if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) { if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) {
@ -455,7 +413,7 @@ JVM_handle_bsd_signal(int sig,
if (StubRoutines::is_safefetch_fault(pc)) { if (StubRoutines::is_safefetch_fault(pc)) {
os::Bsd::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); os::Bsd::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
return 1; return true;
} }
// Handle ALL stack overflow variations here // Handle ALL stack overflow variations here
@ -466,7 +424,7 @@ JVM_handle_bsd_signal(int sig,
if (thread->is_in_full_stack(addr)) { if (thread->is_in_full_stack(addr)) {
// stack overflow // stack overflow
if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) {
return 1; // continue return true; // continue
} }
} }
} }
@ -678,29 +636,6 @@ JVM_handle_bsd_signal(int sig,
return true; return true;
} }
// signal-chaining
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return true;
}
if (!abort_if_unrecognized) {
// caller wants another chance, so give it to him
return false;
}
if (pc == NULL && uc != NULL) {
pc = os::Bsd::ucontext_get_pc(uc);
}
// unmask current signal
sigset_t newset;
sigemptyset(&newset);
sigaddset(&newset, sig);
sigprocmask(SIG_UNBLOCK, &newset, NULL);
VMError::report_and_die(t, sig, pc, info, ucVoid);
ShouldNotReachHere();
return false; return false;
} }

View file

@ -115,16 +115,10 @@ frame os::fetch_frame_from_context(const void* ucVoid) {
return frame(); return frame();
} }
extern "C" JNIEXPORT int bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
JVM_handle_bsd_signal(int sig, ucontext_t* uc, JavaThread* thread) {
siginfo_t* info,
void* ucVoid,
int abort_if_unrecognized) {
ucontext_t* uc = (ucontext_t*) ucVoid;
Thread* t = Thread::current_or_null_safe(); // handle SafeFetch faults the zero way
// handle SafeFetch faults
if (sig == SIGSEGV || sig == SIGBUS) { if (sig == SIGSEGV || sig == SIGBUS) {
sigjmp_buf* const pjb = get_jmp_buf_for_continuation(); sigjmp_buf* const pjb = get_jmp_buf_for_continuation();
if (pjb) { if (pjb) {
@ -132,37 +126,6 @@ JVM_handle_bsd_signal(int sig,
} }
} }
// Note: it's not uncommon that JNI code uses signal/sigset to
// install then restore certain signal handler (e.g. to temporarily
// block SIGPIPE, or have a SIGILL handler when detecting CPU
// type). When that happens, JVM_handle_bsd_signal() might be
// invoked with junk info/ucVoid. To avoid unnecessary crash when
// libjsig is not preloaded, try handle signals that do not require
// siginfo/ucontext first.
if (sig == SIGPIPE || sig == SIGXFSZ) {
// allow chained handler to go first
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return true;
} else {
// Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219
return true;
}
}
JavaThread* thread = NULL;
VMThread* vmthread = NULL;
if (PosixSignals::are_signal_handlers_installed()) {
if (t != NULL ){
if(t->is_Java_thread()) {
thread = t->as_Java_thread();
}
else if(t->is_VM_thread()){
vmthread = (VMThread *)t;
}
}
}
if (info != NULL && thread != NULL) { if (info != NULL && thread != NULL) {
// Handle ALL stack overflow variations here // Handle ALL stack overflow variations here
if (sig == SIGSEGV || sig == SIGBUS) { if (sig == SIGSEGV || sig == SIGBUS) {
@ -202,36 +165,6 @@ JVM_handle_bsd_signal(int sig,
}*/ }*/
} }
// signal-chaining
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return true;
}
if (!abort_if_unrecognized) {
// caller wants another chance, so give it to him
return false;
}
#ifndef PRODUCT
if (sig == SIGSEGV) {
fatal("\n#"
"\n# /--------------------\\"
"\n# | segmentation fault |"
"\n# \\---\\ /--------------/"
"\n# /"
"\n# [-] |\\_/| "
"\n# (+)=C |o o|__ "
"\n# | | =-*-=__\\ "
"\n# OOO c_c_(___)");
}
#endif // !PRODUCT
const char *fmt =
"caught unhandled signal " INT32_FORMAT " at address " PTR_FORMAT;
char buf[128];
sprintf(buf, fmt, sig, info->si_addr);
fatal(buf);
return false; return false;
} }

View file

@ -164,57 +164,9 @@ NOINLINE frame os::current_frame() {
} }
} }
extern "C" JNIEXPORT int bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
JVM_handle_linux_signal(int sig, ucontext_t* uc, JavaThread* thread) {
siginfo_t* info,
void* ucVoid,
int abort_if_unrecognized) {
ucontext_t* uc = (ucontext_t*) ucVoid;
Thread* t = Thread::current_or_null_safe();
// If crash protection is installed we may longjmp away and no destructors
// for objects in this scope will be run.
// So don't use any RAII utilities before crash protection is checked.
os::ThreadCrashProtection::check_crash_protection(sig, t);
// Note: it's not uncommon that JNI code uses signal/sigset to install
// then restore certain signal handler (e.g. to temporarily block SIGPIPE,
// or have a SIGILL handler when detecting CPU type). When that happens,
// JVM_handle_linux_signal() might be invoked with junk info/ucVoid. To
// avoid unnecessary crash when libjsig is not preloaded, try handle signals
// that do not require siginfo/ucontext first.
if (sig == SIGPIPE || sig == SIGXFSZ) {
// allow chained handler to go first
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return true;
} else {
// Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219
return true;
}
}
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
if (handle_assert_poison_fault(ucVoid, info->si_addr)) {
return 1;
}
}
#endif
JavaThread* thread = NULL;
VMThread* vmthread = NULL;
if (PosixSignals::are_signal_handlers_installed()) {
if (t != NULL ){
if(t->is_Java_thread()) {
thread = t->as_Java_thread();
}
else if(t->is_VM_thread()){
vmthread = (VMThread *)t;
}
}
}
/* /*
NOTE: does not seem to work on linux. NOTE: does not seem to work on linux.
if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) { if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) {
@ -235,7 +187,7 @@ JVM_handle_linux_signal(int sig,
if (StubRoutines::is_safefetch_fault(pc)) { if (StubRoutines::is_safefetch_fault(pc)) {
os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
return 1; return true;
} }
address addr = (address) info->si_addr; address addr = (address) info->si_addr;
@ -250,7 +202,7 @@ JVM_handle_linux_signal(int sig,
// check if fault address is within thread stack // check if fault address is within thread stack
if (thread->is_in_full_stack(addr)) { if (thread->is_in_full_stack(addr)) {
if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) {
return 1; // continue return true; // continue
} }
} }
} }
@ -293,10 +245,7 @@ JVM_handle_linux_signal(int sig,
tty->print_cr("trap: %s: (SIGILL)", msg); tty->print_cr("trap: %s: (SIGILL)", msg);
} }
va_list detail_args; return false; // Fatal error
VMError::report_and_die(INTERNAL_ERROR, msg, detail_msg, detail_args, thread,
pc, info, ucVoid, NULL, 0, 0);
va_end(detail_args);
} }
else else
@ -342,30 +291,8 @@ JVM_handle_linux_signal(int sig,
return true; return true;
} }
// signal-chaining return false; // Mute compiler
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return true;
}
if (!abort_if_unrecognized) {
// caller wants another chance, so give it to him
return false;
}
if (pc == NULL && uc != NULL) {
pc = os::Linux::ucontext_get_pc(uc);
}
// unmask current signal
sigset_t newset;
sigemptyset(&newset);
sigaddset(&newset, sig);
sigprocmask(SIG_UNBLOCK, &newset, NULL);
VMError::report_and_die(t, sig, pc, info, ucVoid);
ShouldNotReachHere();
return true; // Mute compiler
} }
void os::Linux::init_thread_fpu_state(void) { void os::Linux::init_thread_fpu_state(void) {

View file

@ -241,18 +241,9 @@ address check_vfp3_32_fault_instr = NULL;
address check_simd_fault_instr = NULL; address check_simd_fault_instr = NULL;
address check_mp_ext_fault_instr = NULL; address check_mp_ext_fault_instr = NULL;
// Utility functions
extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info, bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
void* ucVoid, int abort_if_unrecognized) { ucontext_t* uc, JavaThread* thread) {
ucontext_t* uc = (ucontext_t*) ucVoid;
Thread* t = Thread::current_or_null_safe();
// If crash protection is installed we may longjmp away and no destructors
// for objects in this scope will be run.
// So don't use any RAII utilities before crash protection is checked.
os::ThreadCrashProtection::check_crash_protection(sig, t);
if (sig == SIGILL && if (sig == SIGILL &&
((info->si_addr == (caddr_t)check_simd_fault_instr) ((info->si_addr == (caddr_t)check_simd_fault_instr)
@ -266,44 +257,6 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info,
return true; return true;
} }
// Note: it's not uncommon that JNI code uses signal/sigset to install
// then restore certain signal handler (e.g. to temporarily block SIGPIPE,
// or have a SIGILL handler when detecting CPU type). When that happens,
// JVM_handle_linux_signal() might be invoked with junk info/ucVoid. To
// avoid unnecessary crash when libjsig is not preloaded, try handle signals
// that do not require siginfo/ucontext first.
if (sig == SIGPIPE || sig == SIGXFSZ) {
// allow chained handler to go first
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return true;
} else {
// Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219
return true;
}
}
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
if (handle_assert_poison_fault(ucVoid, info->si_addr)) {
return 1;
}
}
#endif
JavaThread* thread = NULL;
VMThread* vmthread = NULL;
if (PosixSignals::are_signal_handlers_installed()) {
if (t != NULL ){
if(t->is_Java_thread()) {
thread = t->as_Java_thread();
}
else if(t->is_VM_thread()){
vmthread = (VMThread *)t;
}
}
}
address stub = NULL; address stub = NULL;
address pc = NULL; address pc = NULL;
bool unsafe_access = false; bool unsafe_access = false;
@ -317,7 +270,7 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info,
if (StubRoutines::is_safefetch_fault(pc)) { if (StubRoutines::is_safefetch_fault(pc)) {
os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
return 1; return true;
} }
// check if fault address is within thread stack // check if fault address is within thread stack
if (thread->is_in_full_stack(addr)) { if (thread->is_in_full_stack(addr)) {
@ -331,7 +284,7 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info,
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW); stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
} else { } else {
// Thread was in the vm or native code. Return and try to finish. // Thread was in the vm or native code. Return and try to finish.
return 1; return true;
} }
} else if (overflow_state->in_stack_red_zone(addr)) { } else if (overflow_state->in_stack_red_zone(addr)) {
// Fatal red zone violation. Disable the guard pages and fall through // Fatal red zone violation. Disable the guard pages and fall through
@ -347,7 +300,7 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info,
thread->osthread()->set_expanding_stack(); thread->osthread()->set_expanding_stack();
if (os::Linux::manually_expand_stack(thread, addr)) { if (os::Linux::manually_expand_stack(thread, addr)) {
thread->osthread()->clear_expanding_stack(); thread->osthread()->clear_expanding_stack();
return 1; return true;
} }
thread->osthread()->clear_expanding_stack(); thread->osthread()->clear_expanding_stack();
} else { } else {
@ -440,30 +393,8 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info,
return true; return true;
} }
// signal-chaining
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return true;
}
if (!abort_if_unrecognized) {
// caller wants another chance, so give it to him
return false; return false;
}
if (pc == NULL && uc != NULL) {
pc = os::Linux::ucontext_get_pc(uc);
}
// unmask current signal
sigset_t newset;
sigemptyset(&newset);
sigaddset(&newset, sig);
sigprocmask(SIG_UNBLOCK, &newset, NULL);
VMError::report_and_die(t, sig, pc, info, ucVoid);
ShouldNotReachHere();
return false;
} }
void os::Linux::init_thread_fpu_state(void) { void os::Linux::init_thread_fpu_state(void) {

View file

@ -188,32 +188,8 @@ frame os::current_frame() {
return os::get_sender_for_C_frame(&tmp); return os::get_sender_for_C_frame(&tmp);
} }
// Utility functions bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
ucontext_t* uc, JavaThread* thread) {
extern "C" JNIEXPORT int
JVM_handle_linux_signal(int sig,
siginfo_t* info,
void* ucVoid,
int abort_if_unrecognized) {
ucontext_t* uc = (ucontext_t*) ucVoid;
Thread* t = Thread::current_or_null_safe();
// Note: it's not uncommon that JNI code uses signal/sigset to install
// then restore certain signal handler (e.g. to temporarily block SIGPIPE,
// or have a SIGILL handler when detecting CPU type). When that happens,
// JVM_handle_linux_signal() might be invoked with junk info/ucVoid. To
// avoid unnecessary crash when libjsig is not preloaded, try handle signals
// that do not require siginfo/ucontext first.
if (sig == SIGPIPE || sig == SIGXFSZ) {
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return true;
} else {
// Ignoring SIGPIPE - see bugs 4229104
return true;
}
}
// Make the signal handler transaction-aware by checking the existence of a // Make the signal handler transaction-aware by checking the existence of a
// second (transactional) context with MSR TS bits active. If the signal is // second (transactional) context with MSR TS bits active. If the signal is
@ -237,26 +213,6 @@ JVM_handle_linux_signal(int sig,
} }
} }
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
if (handle_assert_poison_fault(ucVoid, info->si_addr)) {
return 1;
}
}
#endif
JavaThread* thread = NULL;
VMThread* vmthread = NULL;
if (PosixSignals::are_signal_handlers_installed()) {
if (t != NULL) {
if(t->is_Java_thread()) {
thread = t->as_Java_thread();
} else if(t->is_VM_thread()) {
vmthread = (VMThread *)t;
}
}
}
// Moved SafeFetch32 handling outside thread!=NULL conditional block to make // Moved SafeFetch32 handling outside thread!=NULL conditional block to make
// it work if no associated JavaThread object exists. // it work if no associated JavaThread object exists.
if (uc) { if (uc) {
@ -297,7 +253,7 @@ JVM_handle_linux_signal(int sig,
if (thread->is_in_full_stack(addr)) { if (thread->is_in_full_stack(addr)) {
// stack overflow // stack overflow
if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) {
return 1; // continue return true; // continue
} }
} }
} }
@ -306,17 +262,6 @@ JVM_handle_linux_signal(int sig,
// Java thread running in Java code => find exception handler if any // Java thread running in Java code => find exception handler if any
// a fault inside compiled code, the interpreter, or a stub // a fault inside compiled code, the interpreter, or a stub
// A VM-related SIGILL may only occur if we are not in the zero page.
// On AIX, we get a SIGILL if we jump to 0x0 or to somewhere else
// in the zero page, because it is filled with 0x0. We ignore
// explicit SIGILLs in the zero page.
if (sig == SIGILL && (pc < (address) 0x200)) {
if (TraceTraps) {
tty->print_raw_cr("SIGILL happened inside zero page.");
}
goto report_and_die;
}
CodeBlob *cb = NULL; CodeBlob *cb = NULL;
int stop_type = -1; int stop_type = -1;
// Handle signal from NativeJump::patch_verified_entry(). // Handle signal from NativeJump::patch_verified_entry().
@ -404,10 +349,7 @@ JVM_handle_linux_signal(int sig,
tty->print_cr("trap: %s: %s (SIGTRAP, stop type %d)", msg, detail_msg, stop_type); tty->print_cr("trap: %s: %s (SIGTRAP, stop type %d)", msg, detail_msg, stop_type);
} }
va_list detail_args; return false; // Fatal error
VMError::report_and_die(INTERNAL_ERROR, msg, detail_msg, detail_args, thread,
pc, info, ucVoid, NULL, 0, 0);
va_end(detail_args);
} }
else if (sig == SIGBUS) { else if (sig == SIGBUS) {
@ -465,31 +407,8 @@ JVM_handle_linux_signal(int sig,
return true; return true;
} }
// signal-chaining
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return true;
}
if (!abort_if_unrecognized) {
// caller wants another chance, so give it to him
return false; return false;
}
if (pc == NULL && uc != NULL) {
pc = os::Linux::ucontext_get_pc(uc);
}
report_and_die:
// unmask current signal
sigset_t newset;
sigemptyset(&newset);
sigaddset(&newset, sig);
sigprocmask(SIG_UNBLOCK, &newset, NULL);
VMError::report_and_die(t, sig, pc, info, ucVoid);
ShouldNotReachHere();
return false;
} }
void os::Linux::init_thread_fpu_state(void) { void os::Linux::init_thread_fpu_state(void) {

View file

@ -204,59 +204,8 @@ frame os::current_frame() {
} }
} }
// Utility functions bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
ucontext_t* uc, JavaThread* thread) {
extern "C" JNIEXPORT int
JVM_handle_linux_signal(int sig,
siginfo_t* info,
void* ucVoid,
int abort_if_unrecognized) {
ucontext_t* uc = (ucontext_t*) ucVoid;
Thread* t = Thread::current_or_null_safe();
// If crash protection is installed we may longjmp away and no destructors
// for objects in this scope will be run.
// So don't use any RAII utilities before crash protection is checked.
os::ThreadCrashProtection::check_crash_protection(sig, t);
// Note: it's not uncommon that JNI code uses signal/sigset to install
// then restore certain signal handler (e.g. to temporarily block SIGPIPE,
// or have a SIGILL handler when detecting CPU type). When that happens,
// JVM_handle_linux_signal() might be invoked with junk info/ucVoid. To
// avoid unnecessary crash when libjsig is not preloaded, try handle signals
// that do not require siginfo/ucontext first.
if (sig == SIGPIPE || sig == SIGXFSZ) {
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return true;
} else {
if (PrintMiscellaneous && (WizardMode || Verbose)) {
warning("Ignoring SIGPIPE - see bug 4229104");
}
return true;
}
}
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
if (handle_assert_poison_fault(ucVoid, info->si_addr)) {
return 1;
}
}
#endif
JavaThread* thread = NULL;
VMThread* vmthread = NULL;
if (PosixSignals::are_signal_handlers_installed()) {
if (t != NULL) {
if(t->is_Java_thread()) {
thread = t->as_Java_thread();
} else if(t->is_VM_thread()) {
vmthread = (VMThread *)t;
}
}
}
// Moved SafeFetch32 handling outside thread!=NULL conditional block to make // Moved SafeFetch32 handling outside thread!=NULL conditional block to make
// it work if no associated JavaThread object exists. // it work if no associated JavaThread object exists.
@ -294,7 +243,7 @@ JVM_handle_linux_signal(int sig,
if (thread->is_in_full_stack(addr)) { if (thread->is_in_full_stack(addr)) {
// stack overflow // stack overflow
if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) {
return 1; // continue return true; // continue
} }
} }
} }
@ -418,38 +367,8 @@ JVM_handle_linux_signal(int sig,
return true; return true;
} }
// signal-chaining
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return true;
}
if (!abort_if_unrecognized) {
// caller wants another chance, so give it to him
return false; return false;
}
if (pc == NULL && uc != NULL) {
pc = os::Linux::ucontext_get_pc(uc);
}
// unmask current signal
sigset_t newset;
sigemptyset(&newset);
sigaddset(&newset, sig);
sigprocmask(SIG_UNBLOCK, &newset, NULL);
// Hand down correct pc for SIGILL, SIGFPE. pc from context
// usually points to the instruction after the failing instruction.
// Note: this should be combined with the trap_pc handling above,
// because it handles the same issue.
if (sig == SIGILL || sig == SIGFPE) {
pc = (address)info->si_addr;
}
VMError::report_and_die(t, sig, pc, info, ucVoid);
ShouldNotReachHere();
return false;
} }
void os::Linux::init_thread_fpu_state(void) { void os::Linux::init_thread_fpu_state(void) {

View file

@ -200,58 +200,10 @@ enum {
trap_page_fault = 0xE trap_page_fault = 0xE
}; };
extern "C" JNIEXPORT int bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
JVM_handle_linux_signal(int sig, ucontext_t* uc, JavaThread* thread) {
siginfo_t* info,
void* ucVoid,
int abort_if_unrecognized) {
ucontext_t* uc = (ucontext_t*) ucVoid;
Thread* t = Thread::current_or_null_safe(); /*
// If crash protection is installed we may longjmp away and no destructors
// for objects in this scope will be run.
// So don't use any RAII utilities before crash protection is checked.
os::ThreadCrashProtection::check_crash_protection(sig, t);
// Note: it's not uncommon that JNI code uses signal/sigset to install
// then restore certain signal handler (e.g. to temporarily block SIGPIPE,
// or have a SIGILL handler when detecting CPU type). When that happens,
// JVM_handle_linux_signal() might be invoked with junk info/ucVoid. To
// avoid unnecessary crash when libjsig is not preloaded, try handle signals
// that do not require siginfo/ucontext first.
if (sig == SIGPIPE || sig == SIGXFSZ) {
// allow chained handler to go first
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return true;
} else {
// Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219
return true;
}
}
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
if (handle_assert_poison_fault(ucVoid, info->si_addr)) {
return 1;
}
}
#endif
JavaThread* thread = NULL;
VMThread* vmthread = NULL;
if (PosixSignals::are_signal_handlers_installed()) {
if (t != NULL ){
if(t->is_Java_thread()) {
thread = t->as_Java_thread();
}
else if(t->is_VM_thread()){
vmthread = (VMThread *)t;
}
}
}
/*
NOTE: does not seem to work on linux. NOTE: does not seem to work on linux.
if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) { if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) {
// can't decode this kind of signal // can't decode this kind of signal
@ -271,7 +223,7 @@ JVM_handle_linux_signal(int sig,
if (StubRoutines::is_safefetch_fault(pc)) { if (StubRoutines::is_safefetch_fault(pc)) {
os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
return 1; return true;
} }
#ifndef AMD64 #ifndef AMD64
@ -292,7 +244,7 @@ JVM_handle_linux_signal(int sig,
if (thread->is_in_full_stack(addr)) { if (thread->is_in_full_stack(addr)) {
// stack overflow // stack overflow
if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) {
return 1; // continue return true; // continue
} }
} }
} }
@ -469,30 +421,7 @@ JVM_handle_linux_signal(int sig,
return true; return true;
} }
// signal-chaining
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return true;
}
if (!abort_if_unrecognized) {
// caller wants another chance, so give it to him
return false; return false;
}
if (pc == NULL && uc != NULL) {
pc = os::Linux::ucontext_get_pc(uc);
}
// unmask current signal
sigset_t newset;
sigemptyset(&newset);
sigaddset(&newset, sig);
sigprocmask(SIG_UNBLOCK, &newset, NULL);
VMError::report_and_die(t, sig, pc, info, ucVoid);
ShouldNotReachHere();
return true; // Mute compiler
} }
void os::Linux::init_thread_fpu_state(void) { void os::Linux::init_thread_fpu_state(void) {

View file

@ -111,14 +111,8 @@ frame os::fetch_frame_from_context(const void* ucVoid) {
return frame(NULL, NULL); // silence compile warnings return frame(NULL, NULL); // silence compile warnings
} }
extern "C" JNIEXPORT int bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
JVM_handle_linux_signal(int sig, ucontext_t* uc, JavaThread* thread) {
siginfo_t* info,
void* ucVoid,
int abort_if_unrecognized) {
ucontext_t* uc = (ucontext_t*) ucVoid;
Thread* t = Thread::current_or_null_safe();
// handle SafeFetch faults // handle SafeFetch faults
if (sig == SIGSEGV || sig == SIGBUS) { if (sig == SIGSEGV || sig == SIGBUS) {
@ -128,37 +122,6 @@ JVM_handle_linux_signal(int sig,
} }
} }
// Note: it's not uncommon that JNI code uses signal/sigset to
// install then restore certain signal handler (e.g. to temporarily
// block SIGPIPE, or have a SIGILL handler when detecting CPU
// type). When that happens, JVM_handle_linux_signal() might be
// invoked with junk info/ucVoid. To avoid unnecessary crash when
// libjsig is not preloaded, try handle signals that do not require
// siginfo/ucontext first.
if (sig == SIGPIPE || sig == SIGXFSZ) {
// allow chained handler to go first
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return true;
} else {
// Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219
return true;
}
}
JavaThread* thread = NULL;
VMThread* vmthread = NULL;
if (PosixSignals::are_signal_handlers_installed()) {
if (t != NULL ){
if(t->is_Java_thread()) {
thread = t->as_Java_thread();
}
else if(t->is_VM_thread()){
vmthread = (VMThread *)t;
}
}
}
if (info != NULL && thread != NULL) { if (info != NULL && thread != NULL) {
// Handle ALL stack overflow variations here // Handle ALL stack overflow variations here
if (sig == SIGSEGV) { if (sig == SIGSEGV) {
@ -216,47 +179,8 @@ JVM_handle_linux_signal(int sig,
}*/ }*/
} }
// signal-chaining return false; // Fatal error
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
return true;
}
if (!abort_if_unrecognized) {
// caller wants another chance, so give it to him
return false;
}
#ifndef PRODUCT
if (sig == SIGSEGV) {
fatal("\n#"
"\n# /--------------------\\"
"\n# | segmentation fault |"
"\n# \\---\\ /--------------/"
"\n# /"
"\n# [-] |\\_/| "
"\n# (+)=C |o o|__ "
"\n# | | =-*-=__\\ "
"\n# OOO c_c_(___)");
}
#endif // !PRODUCT
char buf[128];
char exc_buf[32];
if (os::exception_name(sig, exc_buf, sizeof(exc_buf))) {
bool sent_by_kill = (info != NULL && os::signal_sent_by_kill(info));
snprintf(buf, sizeof(buf), "caught unhandled signal: %s %s",
exc_buf, sent_by_kill ? "(sent by kill)" : "");
} else {
snprintf(buf, sizeof(buf), "caught unhandled signal: %d", sig);
}
// Silence -Wformat-security warning for fatal()
PRAGMA_DIAG_PUSH
PRAGMA_FORMAT_NONLITERAL_IGNORED
fatal(buf);
PRAGMA_DIAG_POP
return true; // silence compiler warnings
} }
void os::Linux::init_thread_fpu_state(void) { void os::Linux::init_thread_fpu_state(void) {

View file

@ -755,7 +755,7 @@ const intx ObjectAlignmentInBytes = 8;
"tables") \ "tables") \
\ \
product(bool, AllowUserSignalHandlers, false, \ product(bool, AllowUserSignalHandlers, false, \
"Do not complain if the application installs signal handlers " \ "Application will install primary signal handlers for the JVM " \
"(Unix only)") \ "(Unix only)") \
\ \
product(bool, UseSignalChaining, true, \ product(bool, UseSignalChaining, true, \

View file

@ -116,9 +116,6 @@ class VMError : public AllStatic {
// and the offending address points into CDS store. // and the offending address points into CDS store.
static void check_failing_cds_access(outputStream* st, const void* siginfo); static void check_failing_cds_access(outputStream* st, const void* siginfo);
static void report_and_die(Thread* thread, unsigned int sig, address pc, void* siginfo,
void* context, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(6, 7);
// Timeout handling. // Timeout handling.
// Hook functions for platform dependend functionality: // Hook functions for platform dependend functionality:
static void reporting_started(); static void reporting_started();
@ -146,6 +143,9 @@ public:
static void print_vm_info(outputStream* st); static void print_vm_info(outputStream* st);
// main error reporting function // main error reporting function
static void report_and_die(Thread* thread, unsigned int sig, address pc, void* siginfo,
void* context, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(6, 7);
static void report_and_die(int id, const char* message, const char* detail_fmt, va_list detail_args, static void report_and_die(int id, const char* message, const char* detail_fmt, va_list detail_args,
Thread* thread, address pc, void* siginfo, void* context, Thread* thread, address pc, void* siginfo, void* context,
const char* filename, int lineno, size_t size) ATTRIBUTE_PRINTF(3, 0); const char* filename, int lineno, size_t size) ATTRIBUTE_PRINTF(3, 0);