/*
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "code/codeCache.hpp"
#include "code/compiledMethod.hpp"
#include "code/nativeInst.hpp"
#include "jvm.h"
#include "logging/log.hpp"
#include "os_posix.hpp"
#include "runtime/atomic.hpp"
#include "runtime/globals.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/os.hpp"
#include "runtime/osThread.hpp"
#include "runtime/safefetch.hpp"
#include "runtime/semaphore.inline.hpp"
#include "runtime/suspendedThreadTask.hpp"
#include "runtime/threadCrashProtection.hpp"
#include "signals_posix.hpp"
#include "suspendResume_posix.hpp"
#include "utilities/events.hpp"
#include "utilities/ostream.hpp"
#include "utilities/vmError.hpp"
#include <signal.h>
static const char* get_signal_name(int sig, char* out, size_t outlen);
// Returns address of a handler associated with the given sigaction
static address get_signal_handler(const struct sigaction* action);
#define HANDLER_IS(handler, address) ((handler) == CAST_FROM_FN_PTR(void*, (address)))
#define HANDLER_IS_IGN(handler) (HANDLER_IS(handler, SIG_IGN))
#define HANDLER_IS_DFL(handler) (HANDLER_IS(handler, SIG_DFL))
#define HANDLER_IS_IGN_OR_DFL(handler) (HANDLER_IS_IGN(handler) || HANDLER_IS_DFL(handler))
// Various signal related mechanism are laid out in the following order:
//
// sun.misc.Signal
// signal chaining
// signal handling (except suspend/resume)
// suspend/resume
// Helper function to strip any flags from a sigaction sa_flag
// which are not needed for semantic comparison (see remarks below
// about SA_RESTORER on Linux).
// Also to work around the fact that not all platforms define sa_flags
// as signed int (looking at you, zlinux).
static int get_sanitized_sa_flags(const struct sigaction* sa) {
int f = (int) sa->sa_flags;
#ifdef LINUX
// Glibc on Linux uses the SA_RESTORER flag to indicate
// the use of a "signal trampoline". We have no interest
// in this flag and need to ignore it when checking our
// own flag settings.
// Note: SA_RESTORER is not exposed through signal.h so we
// have to hardcode its 0x04000000 value here.
const int sa_restorer_flag = 0x04000000;
f &= ~sa_restorer_flag;
#endif // LINUX
return f;
}
// Todo: provide a os::get_max_process_id() or similar. Number of processes
// may have been configured, can be read more accurately from proc fs etc.
#ifndef MAX_PID
#define MAX_PID INT_MAX
#endif
#define IS_VALID_PID(p) (p > 0 && p < MAX_PID)
#define NUM_IMPORTANT_SIGS 32
// At various places we store handler information for each installed handler.
// SavedSignalHandlers is a helper class for those cases, keeping an array of sigaction
// structures.
class SavedSignalHandlers {
// Note: NSIG can be largish, depending on platform, and this array is expected
// to be sparsely populated. To save space the contained structures are
// C-heap allocated. Since they only get added outside of signal handling
// this is no problem.
struct sigaction* _sa[NSIG];
bool check_signal_number(int sig) const {
assert(sig > 0 && sig < NSIG, "invalid signal number %d", sig);
return sig > 0 && sig < NSIG;
}
public:
SavedSignalHandlers() {
::memset(_sa, 0, sizeof(_sa));
}
~SavedSignalHandlers() {
for (int i = 0; i < NSIG; i ++) {
FREE_C_HEAP_OBJ(_sa[i]);
}
}
void set(int sig, const struct sigaction* act) {
if (check_signal_number(sig)) {
assert(_sa[sig] == NULL, "Overwriting signal handler?");
_sa[sig] = NEW_C_HEAP_OBJ(struct sigaction, mtInternal);
*_sa[sig] = *act;
}
}
const struct sigaction* get(int sig) const {
if (check_signal_number(sig)) {
return _sa[sig];
}
return NULL;
}
};
debug_only(static bool signal_sets_initialized = false);
static sigset_t unblocked_sigs, vm_sigs, preinstalled_sigs;
// Our own signal handlers should never ever get replaced by a third party one.
// To check that, and to aid with diagnostics, store a copy of the handler setup
// and compare it periodically against reality (see os::run_periodic_checks()).
static bool check_signals = true;
static SavedSignalHandlers vm_handlers;
static bool do_check_signal_periodically[NSIG] = { 0 };
// For signal-chaining:
// if chaining is active, chained_handlers contains all handlers which we
// replaced with our own and to which we must delegate.
static SavedSignalHandlers chained_handlers;
static bool libjsig_is_loaded = false;
typedef struct sigaction *(*get_signal_t)(int);
static get_signal_t get_signal_action = NULL;
// suspend/resume support
#if defined(__APPLE__)
static OSXSemaphore sr_semaphore;
#else
static PosixSemaphore sr_semaphore;
#endif
// Signal number used to suspend/resume a thread
// do not use any signal number less than SIGSEGV, see 4355769
int PosixSignals::SR_signum = SIGUSR2;
// sun.misc.Signal support
static Semaphore* sig_semaphore = NULL;
// a counter for each possible signal value
static volatile jint pending_signals[NSIG+1] = { 0 };
static const struct {
int sig; const char* name;
} g_signal_info[] = {
{ SIGABRT, "SIGABRT" },
#ifdef SIGAIO
{ SIGAIO, "SIGAIO" },
#endif
{ SIGALRM, "SIGALRM" },
#ifdef SIGALRM1
{ SIGALRM1, "SIGALRM1" },
#endif
{ SIGBUS, "SIGBUS" },
#ifdef SIGCANCEL
{ SIGCANCEL, "SIGCANCEL" },
#endif
{ SIGCHLD, "SIGCHLD" },
#ifdef SIGCLD
{ SIGCLD, "SIGCLD" },
#endif
{ SIGCONT, "SIGCONT" },
#ifdef SIGCPUFAIL
{ SIGCPUFAIL, "SIGCPUFAIL" },
#endif
#ifdef SIGDANGER
{ SIGDANGER, "SIGDANGER" },
#endif
#ifdef SIGDIL
{ SIGDIL, "SIGDIL" },
#endif
#ifdef SIGEMT
{ SIGEMT, "SIGEMT" },
#endif
{ SIGFPE, "SIGFPE" },
#ifdef SIGFREEZE
{ SIGFREEZE, "SIGFREEZE" },
#endif
#ifdef SIGGFAULT
{ SIGGFAULT, "SIGGFAULT" },
#endif
#ifdef SIGGRANT
{ SIGGRANT, "SIGGRANT" },
#endif
{ SIGHUP, "SIGHUP" },
{ SIGILL, "SIGILL" },
#ifdef SIGINFO
{ SIGINFO, "SIGINFO" },
#endif
{ SIGINT, "SIGINT" },
#ifdef SIGIO
{ SIGIO, "SIGIO" },
#endif
#ifdef SIGIOINT
{ SIGIOINT, "SIGIOINT" },
#endif
#ifdef SIGIOT
// SIGIOT is there for BSD compatibility, but on most Unices just a
// synonym for SIGABRT. The result should be "SIGABRT", not
// "SIGIOT".
#if (SIGIOT != SIGABRT )
{ SIGIOT, "SIGIOT" },
#endif
#endif
#ifdef SIGKAP
{ SIGKAP, "SIGKAP" },
#endif
{ SIGKILL, "SIGKILL" },
#ifdef SIGLOST
{ SIGLOST, "SIGLOST" },
#endif
#ifdef SIGLWP
{ SIGLWP, "SIGLWP" },
#endif
#ifdef SIGLWPTIMER
{ SIGLWPTIMER, "SIGLWPTIMER" },
#endif
#ifdef SIGMIGRATE
{ SIGMIGRATE, "SIGMIGRATE" },
#endif
#ifdef SIGMSG
{ SIGMSG, "SIGMSG" },
#endif
{ SIGPIPE, "SIGPIPE" },
#ifdef SIGPOLL
{ SIGPOLL, "SIGPOLL" },
#endif
#ifdef SIGPRE
{ SIGPRE, "SIGPRE" },
#endif
{ SIGPROF, "SIGPROF" },
#ifdef SIGPTY
{ SIGPTY, "SIGPTY" },
#endif
#ifdef SIGPWR
{ SIGPWR, "SIGPWR" },
#endif
{ SIGQUIT, "SIGQUIT" },
#ifdef SIGRECONFIG
{ SIGRECONFIG, "SIGRECONFIG" },
#endif
#ifdef SIGRECOVERY
{ SIGRECOVERY, "SIGRECOVERY" },
#endif
#ifdef SIGRESERVE
{ SIGRESERVE, "SIGRESERVE" },
#endif
#ifdef SIGRETRACT
{ SIGRETRACT, "SIGRETRACT" },
#endif
#ifdef SIGSAK
{ SIGSAK, "SIGSAK" },
#endif
{ SIGSEGV, "SIGSEGV" },
#ifdef SIGSOUND
{ SIGSOUND, "SIGSOUND" },
#endif
#ifdef SIGSTKFLT
{ SIGSTKFLT, "SIGSTKFLT" },
#endif
{ SIGSTOP, "SIGSTOP" },
{ SIGSYS, "SIGSYS" },
#ifdef SIGSYSERROR
{ SIGSYSERROR, "SIGSYSERROR" },
#endif
#ifdef SIGTALRM
{ SIGTALRM, "SIGTALRM" },
#endif
{ SIGTERM, "SIGTERM" },
#ifdef SIGTHAW
{ SIGTHAW, "SIGTHAW" },
#endif
{ SIGTRAP, "SIGTRAP" },
#ifdef SIGTSTP
{ SIGTSTP, "SIGTSTP" },
#endif
{ SIGTTIN, "SIGTTIN" },
{ SIGTTOU, "SIGTTOU" },
#ifdef SIGURG
{ SIGURG, "SIGURG" },
#endif
{ SIGUSR1, "SIGUSR1" },
{ SIGUSR2, "SIGUSR2" },
#ifdef SIGVIRT
{ SIGVIRT, "SIGVIRT" },
#endif
{ SIGVTALRM, "SIGVTALRM" },
#ifdef SIGWAITING
{ SIGWAITING, "SIGWAITING" },
#endif
#ifdef SIGWINCH
{ SIGWINCH, "SIGWINCH" },
#endif
#ifdef SIGWINDOW
{ SIGWINDOW, "SIGWINDOW" },
#endif
{ SIGXCPU, "SIGXCPU" },
{ SIGXFSZ, "SIGXFSZ" },
#ifdef SIGXRES
{ SIGXRES, "SIGXRES" },
#endif
{ -1, NULL }
};
////////////////////////////////////////////////////////////////////////////////
// sun.misc.Signal and BREAK_SIGNAL support
void jdk_misc_signal_init() {
// Initialize signal structures
::memset((void*)pending_signals, 0, sizeof(pending_signals));
// Initialize signal semaphore
sig_semaphore = new Semaphore();
}
void os::signal_notify(int sig) {
if (sig_semaphore != NULL) {
Atomic::inc(&pending_signals[sig]);
sig_semaphore->signal();
} else {
// Signal thread is not created with ReduceSignalUsage and jdk_misc_signal_init
// initialization isn't called.
assert(ReduceSignalUsage, "signal semaphore should be created");
}
}
static int check_pending_signals() {
for (;;) {
for (int i = 0; i < NSIG + 1; i++) {
jint n = pending_signals[i];
if (n > 0 && n == Atomic::cmpxchg(&pending_signals[i], n, n - 1)) {
return i;
}
}
sig_semaphore->wait_with_safepoint_check(JavaThread::current());
}
ShouldNotReachHere();
return 0; // Satisfy compiler
}
int os::signal_wait() {
return check_pending_signals();
}
////////////////////////////////////////////////////////////////////////////////
// signal chaining support
struct sigaction* get_chained_signal_action(int sig) {
struct sigaction *actp = NULL;
if (libjsig_is_loaded) {
// Retrieve the old signal handler from libjsig
actp = (*get_signal_action)(sig);
}
if (actp == NULL) {
// Retrieve the preinstalled signal handler from jvm
actp = const_cast<struct sigaction*>(chained_handlers.get(sig));
}
return actp;
}
static bool call_chained_handler(struct sigaction *actp, int sig,
siginfo_t *siginfo, void *context) {
// Call the old signal handler
if (actp->sa_handler == SIG_DFL) {
// It's more reasonable to let jvm treat it as an unexpected exception
// instead of taking the default action.
return false;
} else if (actp->sa_handler != SIG_IGN) {
if ((actp->sa_flags & SA_NODEFER) == 0) {
// automatically block the signal
sigaddset(&(actp->sa_mask), sig);
}
sa_handler_t hand = NULL;
sa_sigaction_t sa = NULL;
bool siginfo_flag_set = (actp->sa_flags & SA_SIGINFO) != 0;
// retrieve the chained handler
if (siginfo_flag_set) {
sa = actp->sa_sigaction;
} else {
hand = actp->sa_handler;
}
if ((actp->sa_flags & SA_RESETHAND) != 0) {
actp->sa_handler = SIG_DFL;
}
// try to honor the signal mask
sigset_t oset;
sigemptyset(&oset);
pthread_sigmask(SIG_SETMASK, &(actp->sa_mask), &oset);
// call into the chained handler
if (siginfo_flag_set) {
(*sa)(sig, siginfo, context);
} else {
(*hand)(sig);
}
// restore the signal mask
pthread_sigmask(SIG_SETMASK, &oset, NULL);
}
// Tell jvm's signal handler the signal is taken care of.
return true;
}
bool PosixSignals::chained_handler(int sig, siginfo_t* siginfo, void* context) {
bool chained = false;
// signal-chaining
if (UseSignalChaining) {
struct sigaction *actp = get_chained_signal_action(sig);
if (actp != NULL) {
chained = call_chained_handler(actp, sig, siginfo, context);
}
}
return chained;
}
///// Synchronous (non-deferrable) error signals (ILL, SEGV, FPE, BUS, TRAP):
// These signals are special because they cannot be deferred and, if they
// happen while delivery is blocked for the receiving thread, will cause UB
// (in practice typically resulting in sudden process deaths or hangs, see
// JDK-8252533). So we must take care never to block them when we cannot be
// absolutely sure they won't happen. In practice, this is always.
//
// Relevant Posix quote:
// "The behavior of a process is undefined after it ignores a SIGFPE, SIGILL,
// SIGSEGV, or SIGBUS signal that was not generated by kill(), sigqueue(), or
// raise()."
//
// We also include SIGTRAP in that list of never-to-block-signals. While not
// mentioned by the Posix documentation, in our (SAPs) experience blocking it
// causes similar problems. Beside, during normal operation - outside of error
// handling - SIGTRAP may be used for implicit NULL checking, so it makes sense
// to never block it.
//
// We deal with those signals in two ways:
// - we just never explicitly block them, which includes not accidentally blocking
// them via sa_mask when establishing signal handlers.
// - as an additional safety measure, at the entrance of a signal handler, we
// unblock them explicitly.
static void add_error_signals_to_set(sigset_t* set) {
sigaddset(set, SIGILL);
sigaddset(set, SIGBUS);
sigaddset(set, SIGFPE);
sigaddset(set, SIGSEGV);
sigaddset(set, SIGTRAP);
}
static void remove_error_signals_from_set(sigset_t* set) {
sigdelset(set, SIGILL);
sigdelset(set, SIGBUS);
sigdelset(set, SIGFPE);
sigdelset(set, SIGSEGV);
sigdelset(set, SIGTRAP);
}
// Unblock all signals whose delivery cannot be deferred and which, if they happen
// while delivery is blocked, would cause crashes or hangs (JDK-8252533).
void PosixSignals::unblock_error_signals() {
sigset_t set;
sigemptyset(&set);
add_error_signals_to_set(&set);
::pthread_sigmask(SIG_UNBLOCK, &set, NULL);
}
class ErrnoPreserver: public StackObj {
const int _saved;
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();
ucontext_t* const uc = (ucontext_t*) ucVoid;
Thread* const t = Thread::current_or_null_safe();
// Handle JFR thread crash protection.
// Note: this may cause us to longjmp away. Do not use any code before this
// point which really needs any form of epilogue code running, eg RAII objects.
ThreadCrashProtection::check_crash_protection(sig, t);
bool signal_was_handled = false;
// Handle assertion poison page accesses.
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
if (!signal_was_handled &&
((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison)) {
signal_was_handled = handle_assert_poison_fault(ucVoid, info->si_addr);
}
#endif
// Extract pc from context. Note that for certain signals and certain
// architectures the pc in ucontext_t will point *after* the offending
// instruction. In those cases, use siginfo si_addr instead.
address pc = NULL;
if (uc != NULL) {
if (S390_ONLY(sig == SIGILL || sig == SIGFPE) NOT_S390(false)) {
pc = (address)info->si_addr;
} else {
pc = os::Posix::ucontext_get_pc(uc);
}
}
if (!signal_was_handled) {
signal_was_handled = handle_safefetch(sig, pc, uc);
}
// Ignore SIGPIPE and SIGXFSZ (4229104, 6499219).
if (!signal_was_handled &&
(sig == SIGPIPE || sig == SIGXFSZ)) {
PosixSignals::chained_handler(sig, info, ucVoid);
signal_was_handled = true; // unconditionally.
}
#ifndef ZERO
// Check for UD trap caused by NOP patching.
// If it is, patch return address to be deopt handler.
if (!signal_was_handled && pc != NULL && os::is_readable_pointer(pc)) {
if (NativeDeoptInstruction::is_deopt_at(pc)) {
CodeBlob* cb = CodeCache::find_blob(pc);
if (cb != NULL && cb->is_compiled()) {
MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, t);) // can call PcDescCache::add_pc_desc
CompiledMethod* cm = cb->as_compiled_method();
assert(cm->insts_contains_inclusive(pc), "");
address deopt = cm->is_method_handle_return(pc) ?
cm->deopt_mh_handler_begin() :
cm->deopt_handler_begin();
assert(deopt != NULL, "");
frame fr = os::fetch_frame_from_context(uc);
cm->set_original_pc(&fr, pc);
os::Posix::ucontext_set_pc(uc, deopt);
signal_was_handled = true;
}
}
}
#endif // !ZERO
// 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) {
VMError::report_and_die(t, sig, pc, info, ucVoid);
// 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* context) {
// 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, context, true);
}
static void UserHandler(int sig, siginfo_t* siginfo, void* context) {
PosixSignals::unblock_error_signals();
// Ctrl-C is pressed during error reporting, likely because the error
// handler fails to abort. Let VM die immediately.
if (sig == SIGINT && VMError::is_error_reported()) {
os::die();
}
os::signal_notify(sig);
}
static void print_signal_handler_name(outputStream* os, address handler, char* buf, size_t buflen) {
// We demangle, but omit arguments - signal handlers should have always the same prototype.
os::print_function_and_library_name(os, handler, buf, buflen,
true, // shorten_path
true, // demangle
true // omit arguments
);
}
// Writes one-line description of a combination of sigaction.sa_flags into a user
// provided buffer. Returns that buffer.
static const char* describe_sa_flags(int flags, char* buffer, size_t size) {
char* p = buffer;
size_t remaining = size;
bool first = true;
int idx = 0;
assert(buffer, "invalid argument");
if (size == 0) {
return buffer;
}
strncpy(buffer, "none", size);
const unsigned int unknown_flag = ~(SA_NOCLDSTOP |
SA_ONSTACK |
SA_NOCLDSTOP |
SA_RESTART |
SA_SIGINFO |
SA_NOCLDWAIT |
SA_NODEFER
AIX_ONLY(| SA_OLDSTYLE)
);
const struct {
// NB: i is an unsigned int here because SA_RESETHAND is on some
// systems 0x80000000, which is implicitly unsigned. Assigning
// it to an int field would be an overflow in unsigned-to-signed
// conversion.
unsigned int i;
const char* s;
} flaginfo [] = {
{ SA_NOCLDSTOP, "SA_NOCLDSTOP" },
{ SA_ONSTACK, "SA_ONSTACK" },
{ SA_RESETHAND, "SA_RESETHAND" },
{ SA_RESTART, "SA_RESTART" },
{ SA_SIGINFO, "SA_SIGINFO" },
{ SA_NOCLDWAIT, "SA_NOCLDWAIT" },
{ SA_NODEFER, "SA_NODEFER" },
#if defined(AIX)
{ SA_OLDSTYLE, "SA_OLDSTYLE" },
#endif
{ unknown_flag, "NOT USED" }
};
for (idx = 0; flaginfo[idx].i != unknown_flag && remaining > 1; idx++) {
if (flags & flaginfo[idx].i) {
if (first) {
jio_snprintf(p, remaining, "%s", flaginfo[idx].s);
first = false;
} else {
jio_snprintf(p, remaining, "|%s", flaginfo[idx].s);
}
const size_t len = strlen(p);
p += len;
remaining -= len;
}
}
unsigned int unknowns = flags & unknown_flag;
if (unknowns != 0) {
jio_snprintf(p, remaining, "|Unknown_flags:%x", unknowns);
}
buffer[size - 1] = '\0';
return buffer;
}
// Prints one-line description of a combination of sigaction.sa_flags.
static void print_sa_flags(outputStream* st, int flags) {
char buffer[0x100];
describe_sa_flags(flags, buffer, sizeof(buffer));
st->print("%s", buffer);
}
// Implementation may use the same storage for both the sa_sigaction field and the sa_handler field,
// so check for "sigAct.sa_flags == SA_SIGINFO"
static address get_signal_handler(const struct sigaction* action) {
bool siginfo_flag_set = (action->sa_flags & SA_SIGINFO) != 0;
if (siginfo_flag_set) {
return CAST_FROM_FN_PTR(address, action->sa_sigaction);
} else {
return CAST_FROM_FN_PTR(address, action->sa_handler);
}
}
typedef int (*os_sigaction_t)(int, const struct sigaction *, struct sigaction *);
static void SR_handler(int sig, siginfo_t* siginfo, void* context);
// Semantically compare two sigaction structures. Return true if they are referring to
// the same handler, using the same flags.
static bool are_actions_equal(const struct sigaction* sa,
const struct sigaction* expected_sa) {
address this_handler = get_signal_handler(sa);
address expected_handler = get_signal_handler(expected_sa);
const int this_flags = get_sanitized_sa_flags(sa);
const int expected_flags = get_sanitized_sa_flags(expected_sa);
return (this_handler == expected_handler) &&
(this_flags == expected_flags);
}
// If we installed one of our signal handlers for sig, check that the current
// setup matches what we originally installed. Return true if signal handler
// is different. Otherwise, return false;
static bool check_signal_handler(int sig) {
char buf[O_BUFLEN];
bool mismatch = false;
if (!do_check_signal_periodically[sig]) {
return false;
}
const struct sigaction* expected_act = vm_handlers.get(sig);
assert(expected_act != NULL, "Sanity");
// Retrieve current signal setup.
struct sigaction act;
static os_sigaction_t os_sigaction = NULL;
if (os_sigaction == NULL) {
// only trust the default sigaction, in case it has been interposed
os_sigaction = (os_sigaction_t)dlsym(RTLD_DEFAULT, "sigaction");
if (os_sigaction == NULL) return false;
}
os_sigaction(sig, (struct sigaction*)NULL, &act);
// Compare both sigaction structures (intelligently; only the members we care about).
// Ignore if the handler is our own crash handler.
if (!are_actions_equal(&act, expected_act) &&
!(HANDLER_IS(get_signal_handler(&act), VMError::crash_handler_address))) {
tty->print_cr("Warning: %s handler modified!", os::exception_name(sig, buf, sizeof(buf)));
// If we had a mismatch:
// - Disable any further checks for this signal - we do not want to flood stdout. Though
// depending on which signal had been overwritten, we may die very soon anyway.
do_check_signal_periodically[sig] = false;
// Running under non-interactive shell, SHUTDOWN2_SIGNAL will be reassigned SIG_IGN
if (sig == SHUTDOWN2_SIGNAL && !isatty(fileno(stdin))) {
tty->print_cr("Note: Running in non-interactive shell, %s handler is replaced by shell",
os::exception_name(sig, buf, O_BUFLEN));
}
return true;
}
return false;
}
void* PosixSignals::user_handler() {
return CAST_FROM_FN_PTR(void*, UserHandler);
}
// Used by JVM_RegisterSignal to install a signal handler.
// The allowed set of signals is restricted by the caller.
// The incoming handler is one of:
// - psuedo-handler: SIG_IGN or SIG_DFL
// - the VM's UserHandler of type sa_sigaction_t
// - unknown signal handling function which we assume is also
// of type sa_sigaction_t - this is a bug - see JDK-8295702
// Returns the currently installed handler.
void* PosixSignals::install_generic_signal_handler(int sig, void* handler) {
struct sigaction sigAct, oldSigAct;
sigfillset(&(sigAct.sa_mask));
remove_error_signals_from_set(&(sigAct.sa_mask));
sigAct.sa_flags = SA_RESTART;
if (HANDLER_IS_IGN_OR_DFL(handler)) {
sigAct.sa_handler = CAST_TO_FN_PTR(sa_handler_t, handler);
} else {
sigAct.sa_flags |= SA_SIGINFO;
sigAct.sa_sigaction = CAST_TO_FN_PTR(sa_sigaction_t, handler);
}
if (sigaction(sig, &sigAct, &oldSigAct)) {
// -1 means registration failed
return (void *)-1;
}
return get_signal_handler(&oldSigAct);
}
// Installs the given sigaction handler for the given signal.
// - sigAct: the new struct sigaction to be filled in and used
// for this signal. The caller must provide this as it
// may need to be stored/accessed by that caller.
// - oldSigAct: the old struct sigaction that was associated with
// this signal
// Returns 0 on success and -1 on error.
int PosixSignals::install_sigaction_signal_handler(struct sigaction* sigAct,
struct sigaction* oldSigAct,
int sig,
sa_sigaction_t handler) {
sigfillset(&sigAct->sa_mask);
remove_error_signals_from_set(&sigAct->sa_mask);
sigAct->sa_sigaction = handler;
sigAct->sa_flags = SA_SIGINFO|SA_RESTART;
#if defined(__APPLE__)
// 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"
// if the signal handler declares it will handle it on alternate stack.
// Notice we only declare we will handle it on alt stack, but we are not
// actually going to use real alt stack - this is just a workaround.
// Please see ux_exception.c, method catch_mach_exception_raise for details
// link http://www.opensource.apple.com/source/xnu/xnu-2050.18.24/bsd/uxkern/ux_exception.c
if (sig == SIGSEGV) {
sigAct->sa_flags |= SA_ONSTACK;
}
#endif
return sigaction(sig, sigAct, oldSigAct);
}
// Will be modified when max signal is changed to be dynamic
int os::sigexitnum_pd() {
return NSIG;
}
// This method is a periodic task to check for misbehaving JNI applications
// under CheckJNI, we can add any periodic checks here
void os::run_periodic_checks(outputStream* st) {
if (check_signals == false) return;
// SEGV and BUS if overridden could potentially prevent
// generation of hs*.log in the event of a crash, debugging
// such a case can be very challenging, so we absolutely
// check the following for a good measure:
bool print_handlers = false;
print_handlers |= check_signal_handler(SIGSEGV);
print_handlers |= check_signal_handler(SIGILL);
print_handlers |= check_signal_handler(SIGFPE);
print_handlers |= check_signal_handler(SIGBUS);
print_handlers |= check_signal_handler(SIGPIPE);
print_handlers |= check_signal_handler(SIGXFSZ);
PPC64_ONLY(print_handlers |= check_signal_handler(SIGTRAP);)
// ReduceSignalUsage allows the user to override these handlers
// see comments at the very top and jvm_md.h
if (!ReduceSignalUsage) {
print_handlers |= check_signal_handler(SHUTDOWN1_SIGNAL);
print_handlers |= check_signal_handler(SHUTDOWN2_SIGNAL);
print_handlers |= check_signal_handler(SHUTDOWN3_SIGNAL);
print_handlers |= check_signal_handler(BREAK_SIGNAL);
}
print_handlers |= check_signal_handler(PosixSignals::SR_signum);
if (print_handlers) {
// If we had a mismatch:
// - print all signal handlers. As part of that printout, details will be printed
// about any modified handlers.
char buf[O_BUFLEN];
os::print_signal_handlers(st, buf, O_BUFLEN);
st->print_cr("Consider using jsig library.");
}
}
// Helper function for PosixSignals::print_siginfo_...():
// return a textual description for signal code.
struct enum_sigcode_desc_t {
const char* s_name;
const char* s_desc;
};
static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t* out) {
const struct {
int sig; int code; const char* s_code; const char* s_desc;
} t1 [] = {
{ SIGILL, ILL_ILLOPC, "ILL_ILLOPC", "Illegal opcode." },
{ SIGILL, ILL_ILLOPN, "ILL_ILLOPN", "Illegal operand." },
{ SIGILL, ILL_ILLADR, "ILL_ILLADR", "Illegal addressing mode." },
{ SIGILL, ILL_ILLTRP, "ILL_ILLTRP", "Illegal trap." },
{ SIGILL, ILL_PRVOPC, "ILL_PRVOPC", "Privileged opcode." },
{ SIGILL, ILL_PRVREG, "ILL_PRVREG", "Privileged register." },
{ SIGILL, ILL_COPROC, "ILL_COPROC", "Coprocessor error." },
{ SIGILL, ILL_BADSTK, "ILL_BADSTK", "Internal stack error." },
#if defined(IA64) && defined(LINUX)
{ SIGILL, ILL_BADIADDR, "ILL_BADIADDR", "Unimplemented instruction address" },
{ SIGILL, ILL_BREAK, "ILL_BREAK", "Application Break instruction" },
#endif
{ SIGFPE, FPE_INTDIV, "FPE_INTDIV", "Integer divide by zero." },
{ SIGFPE, FPE_INTOVF, "FPE_INTOVF", "Integer overflow." },
{ SIGFPE, FPE_FLTDIV, "FPE_FLTDIV", "Floating-point divide by zero." },
{ SIGFPE, FPE_FLTOVF, "FPE_FLTOVF", "Floating-point overflow." },
{ SIGFPE, FPE_FLTUND, "FPE_FLTUND", "Floating-point underflow." },
{ SIGFPE, FPE_FLTRES, "FPE_FLTRES", "Floating-point inexact result." },
{ SIGFPE, FPE_FLTINV, "FPE_FLTINV", "Invalid floating-point operation." },
{ SIGFPE, FPE_FLTSUB, "FPE_FLTSUB", "Subscript out of range." },
{ SIGSEGV, SEGV_MAPERR, "SEGV_MAPERR", "Address not mapped to object." },
{ SIGSEGV, SEGV_ACCERR, "SEGV_ACCERR", "Invalid permissions for mapped object." },
#if defined(AIX)
// no explanation found what keyerr would be
{ SIGSEGV, SEGV_KEYERR, "SEGV_KEYERR", "key error" },
#endif
#if defined(IA64) && !defined(AIX)
{ SIGSEGV, SEGV_PSTKOVF, "SEGV_PSTKOVF", "Paragraph stack overflow" },
#endif
{ SIGBUS, BUS_ADRALN, "BUS_ADRALN", "Invalid address alignment." },
{ SIGBUS, BUS_ADRERR, "BUS_ADRERR", "Nonexistent physical address." },
{ SIGBUS, BUS_OBJERR, "BUS_OBJERR", "Object-specific hardware error." },
{ SIGTRAP, TRAP_BRKPT, "TRAP_BRKPT", "Process breakpoint." },
{ SIGTRAP, TRAP_TRACE, "TRAP_TRACE", "Process trace trap." },
{ SIGCHLD, CLD_EXITED, "CLD_EXITED", "Child has exited." },
{ SIGCHLD, CLD_KILLED, "CLD_KILLED", "Child has terminated abnormally and did not create a core file." },
{ SIGCHLD, CLD_DUMPED, "CLD_DUMPED", "Child has terminated abnormally and created a core file." },
{ SIGCHLD, CLD_TRAPPED, "CLD_TRAPPED", "Traced child has trapped." },
{ SIGCHLD, CLD_STOPPED, "CLD_STOPPED", "Child has stopped." },
{ SIGCHLD, CLD_CONTINUED,"CLD_CONTINUED","Stopped child has continued." },
#ifdef SIGPOLL
{ SIGPOLL, POLL_OUT, "POLL_OUT", "Output buffers available." },
{ SIGPOLL, POLL_MSG, "POLL_MSG", "Input message available." },
{ SIGPOLL, POLL_ERR, "POLL_ERR", "I/O error." },
{ SIGPOLL, POLL_PRI, "POLL_PRI", "High priority input available." },
{ SIGPOLL, POLL_HUP, "POLL_HUP", "Device disconnected. [Option End]" },
#endif
{ -1, -1, NULL, NULL }
};
// Codes valid in any signal context.
const struct {
int code; const char* s_code; const char* s_desc;
} t2 [] = {
{ SI_USER, "SI_USER", "Signal sent by kill()." },
{ SI_QUEUE, "SI_QUEUE", "Signal sent by the sigqueue()." },
{ SI_TIMER, "SI_TIMER", "Signal generated by expiration of a timer set by timer_settime()." },
{ SI_ASYNCIO, "SI_ASYNCIO", "Signal generated by completion of an asynchronous I/O request." },
{ SI_MESGQ, "SI_MESGQ", "Signal generated by arrival of a message on an empty message queue." },
// Linux specific
#ifdef SI_TKILL
{ SI_TKILL, "SI_TKILL", "Signal sent by tkill (pthread_kill)" },
#endif
#ifdef SI_DETHREAD
{ SI_DETHREAD, "SI_DETHREAD", "Signal sent by execve() killing subsidiary threads" },
#endif
#ifdef SI_KERNEL
{ SI_KERNEL, "SI_KERNEL", "Signal sent by kernel." },
#endif
#ifdef SI_SIGIO
{ SI_SIGIO, "SI_SIGIO", "Signal sent by queued SIGIO" },
#endif
#if defined(AIX)
{ SI_UNDEFINED, "SI_UNDEFINED","siginfo contains partial information" },
{ SI_EMPTY, "SI_EMPTY", "siginfo contains no useful information" },
#endif
{ -1, NULL, NULL }
};
const char* s_code = NULL;
const char* s_desc = NULL;
for (int i = 0; t1[i].sig != -1; i ++) {
if (t1[i].sig == si->si_signo && t1[i].code == si->si_code) {
s_code = t1[i].s_code;
s_desc = t1[i].s_desc;
break;
}
}
if (s_code == NULL) {
for (int i = 0; t2[i].s_code != NULL; i ++) {
if (t2[i].code == si->si_code) {
s_code = t2[i].s_code;
s_desc = t2[i].s_desc;
}
}
}
if (s_code == NULL) {
out->s_name = "unknown";
out->s_desc = "unknown";
return false;
}
out->s_name = s_code;
out->s_desc = s_desc;
return true;
}
bool os::signal_sent_by_kill(const void* siginfo) {
const siginfo_t* const si = (const siginfo_t*)siginfo;
return si->si_code == SI_USER || si->si_code == SI_QUEUE
#ifdef SI_TKILL
|| si->si_code == SI_TKILL
#endif
;
}
// Returns true if signal number is valid.
static bool is_valid_signal(int sig) {
// MacOS not really POSIX compliant: sigaddset does not return
// an error for invalid signal numbers. However, MacOS does not
// support real time signals and simply seems to have just 33
// signals with no holes in the signal range.
#if defined(__APPLE__)
return sig >= 1 && sig < NSIG;
#else
// Use sigaddset to check for signal validity.
sigset_t set;
sigemptyset(&set);
if (sigaddset(&set, sig) == -1 && errno == EINVAL) {
return false;
}
return true;
#endif
}
static const char* get_signal_name(int sig, char* out, size_t outlen) {
const char* ret = NULL;
#ifdef SIGRTMIN
if (sig >= SIGRTMIN && sig <= SIGRTMAX) {
if (sig == SIGRTMIN) {
ret = "SIGRTMIN";
} else if (sig == SIGRTMAX) {
ret = "SIGRTMAX";
} else {
jio_snprintf(out, outlen, "SIGRTMIN+%d", sig - SIGRTMIN);
return out;
}
}
#endif
if (sig > 0) {
for (int idx = 0; g_signal_info[idx].sig != -1; idx ++) {
if (g_signal_info[idx].sig == sig) {
ret = g_signal_info[idx].name;
break;
}
}
}
if (!ret) {
if (!is_valid_signal(sig)) {
ret = "INVALID";
} else {
ret = "UNKNOWN";
}
}
if (out && outlen > 0) {
strncpy(out, ret, outlen);
out[outlen - 1] = '\0';
}
return out;
}
void os::print_siginfo(outputStream* os, const void* si0) {
const siginfo_t* const si = (const siginfo_t*) si0;
char buf[20];
os->print("siginfo:");
if (!si) {
os->print(" ");
return;
}
const int sig = si->si_signo;
os->print(" si_signo: %d (%s)", sig, get_signal_name(sig, buf, sizeof(buf)));
enum_sigcode_desc_t ed;
get_signal_code_description(si, &ed);
os->print(", si_code: %d (%s)", si->si_code, ed.s_name);
if (si->si_errno) {
os->print(", si_errno: %d", si->si_errno);
}
// Output additional information depending on the signal code.
// Note: Many implementations lump si_addr, si_pid, si_uid etc. together as unions,
// so it depends on the context which member to use. For synchronous error signals,
// we print si_addr, unless the signal was sent by another process or thread, in
// which case we print out pid or tid of the sender.
if (os::signal_sent_by_kill(si)) {
const pid_t pid = si->si_pid;
os->print(", si_pid: %ld", (long) pid);
if (IS_VALID_PID(pid)) {
const pid_t me = getpid();
if (me == pid) {
os->print(" (current process)");
}
} else {
os->print(" (invalid)");
}
os->print(", si_uid: %ld", (long) si->si_uid);
if (sig == SIGCHLD) {
os->print(", si_status: %d", si->si_status);
}
} else if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
sig == SIGTRAP || sig == SIGFPE) {
os->print(", si_addr: " PTR_FORMAT, p2i(si->si_addr));
#ifdef SIGPOLL
} else if (sig == SIGPOLL) {
// siginfo_t.si_band is defined as "long", and it is so in most
// implementations. But SPARC64 glibc has a bug: si_band is "int".
// Cast si_band to "long" to prevent format specifier mismatch.
// See: https://sourceware.org/bugzilla/show_bug.cgi?id=23821
os->print(", si_band: %ld", (long) si->si_band);
#endif
}
}
bool os::signal_thread(Thread* thread, int sig, const char* reason) {
OSThread* osthread = thread->osthread();
if (osthread) {
int status = pthread_kill(osthread->pthread_id(), sig);
if (status == 0) {
Events::log(Thread::current(), "sent signal %d to Thread " INTPTR_FORMAT " because %s.",
sig, p2i(thread), reason);
return true;
}
}
return false;
}
// Returns:
// NULL for an invalid signal number
// "SIG<num>" for a valid but unknown signal number
// signal name otherwise.
const char* os::exception_name(int sig, char* buf, size_t size) {
if (!is_valid_signal(sig)) {
return NULL;
}
const char* const name = get_signal_name(sig, buf, size);
if (strcmp(name, "UNKNOWN") == 0) {
jio_snprintf(buf, size, "SIG%d", sig);
}
return buf;
}
int os::get_signal_number(const char* signal_name) {
char tmp[30];
const char* s = signal_name;
if (s[0] != 'S' || s[1] != 'I' || s[2] != 'G') {
jio_snprintf(tmp, sizeof(tmp), "SIG%s", signal_name);
s = tmp;
}
for (int idx = 0; g_signal_info[idx].sig != -1; idx ++) {
if (strcmp(g_signal_info[idx].name, s) == 0) {
return g_signal_info[idx].sig;
}
}
return -1;
}
void set_signal_handler(int sig) {
// Check for overwrite.
struct sigaction oldAct;
sigaction(sig, (struct sigaction*)NULL, &oldAct);
// Query the current signal handler. Needs to be a separate operation
// from installing a new handler since we need to honor AllowUserSignalHandlers.
void* oldhand = get_signal_handler(&oldAct);
if (!HANDLER_IS_IGN_OR_DFL(oldhand) &&
!HANDLER_IS(oldhand, javaSignalHandler)) {
if (AllowUserSignalHandlers) {
// Do not overwrite; user takes responsibility to forward to us.
return;
} else if (UseSignalChaining) {
// save the old handler in jvm
chained_handlers.set(sig, &oldAct);
// libjsig also interposes the sigaction() call below and saves the
// old sigaction on it own.
} else {
fatal("Encountered unexpected pre-existing sigaction handler "
"%#lx for signal %d.", (long)oldhand, sig);
}
}
struct sigaction sigAct;
int ret = PosixSignals::install_sigaction_signal_handler(&sigAct, &oldAct,
sig, javaSignalHandler);
assert(ret == 0, "check");
// Save handler setup for possible later checking
vm_handlers.set(sig, &sigAct);
do_check_signal_periodically[sig] = true;
#ifdef ASSERT
void* oldhand2 = get_signal_handler(&oldAct);
assert(oldhand2 == oldhand, "no concurrent signal handler installation");
#endif
}
// install signal handlers for signals that HotSpot needs to
// handle in order to support Java-level exception handling.
void install_signal_handlers() {
// signal-chaining
typedef void (*signal_setting_t)();
signal_setting_t begin_signal_setting = NULL;
signal_setting_t end_signal_setting = NULL;
begin_signal_setting = CAST_TO_FN_PTR(signal_setting_t,
dlsym(RTLD_DEFAULT, "JVM_begin_signal_setting"));
if (begin_signal_setting != NULL) {
end_signal_setting = CAST_TO_FN_PTR(signal_setting_t,
dlsym(RTLD_DEFAULT, "JVM_end_signal_setting"));
get_signal_action = CAST_TO_FN_PTR(get_signal_t,
dlsym(RTLD_DEFAULT, "JVM_get_signal_action"));
libjsig_is_loaded = true;
assert(UseSignalChaining, "should enable signal-chaining");
}
if (libjsig_is_loaded) {
// Tell libjsig jvm is setting signal handlers
(*begin_signal_setting)();
}
set_signal_handler(SIGSEGV);
set_signal_handler(SIGPIPE);
set_signal_handler(SIGBUS);
set_signal_handler(SIGILL);
set_signal_handler(SIGFPE);
PPC64_ONLY(set_signal_handler(SIGTRAP);)
set_signal_handler(SIGXFSZ);
if (!ReduceSignalUsage) {
// Install BREAK_SIGNAL's handler in early initialization phase, in
// order to reduce the risk that an attach client accidentally forces
// HotSpot to quit prematurely.
// The actual work for handling BREAK_SIGNAL is performed by the Signal
// Dispatcher thread, which is created and started at a much later point,
// see os::initialize_jdk_signal_support(). Any BREAK_SIGNAL received
// before the Signal Dispatcher thread is started is queued up via the
// pending_signals[BREAK_SIGNAL] counter, and will be processed by the
// Signal Dispatcher thread in a delayed fashion.
//
// Also note that HotSpot does NOT support signal chaining for BREAK_SIGNAL.
// Applications that require a custom BREAK_SIGNAL handler should run with
// -XX:+ReduceSignalUsage. Otherwise if libjsig is used together with
// -XX:+ReduceSignalUsage, libjsig will prevent changing BREAK_SIGNAL's
// handler to a custom handler.
struct sigaction sigAct, oldSigAct;
int ret = PosixSignals::install_sigaction_signal_handler(&sigAct, &oldSigAct,
BREAK_SIGNAL, UserHandler);
assert(ret == 0, "check");
}
#if defined(__APPLE__)
// lldb (gdb) installs both standard BSD signal handlers, and mach exception
// handlers. By replacing the existing task exception handler, we disable lldb's mach
// exception handling, while leaving the standard BSD signal handlers functional.
//
// EXC_MASK_BAD_ACCESS needed by all architectures for NULL ptr checking
// EXC_MASK_ARITHMETIC needed by all architectures for div by 0 checking
// EXC_MASK_BAD_INSTRUCTION needed by aarch64 to initiate deoptimization
kern_return_t kr;
kr = task_set_exception_ports(mach_task_self(),
EXC_MASK_BAD_ACCESS | EXC_MASK_ARITHMETIC
AARCH64_ONLY(| EXC_MASK_BAD_INSTRUCTION),
MACH_PORT_NULL,
EXCEPTION_STATE_IDENTITY,
MACHINE_THREAD_STATE);
assert(kr == KERN_SUCCESS, "could not set mach task signal handler");
#endif
if (libjsig_is_loaded) {
// Tell libjsig jvm finishes setting signal handlers
(*end_signal_setting)();
}
// We don't activate signal checker if libjsig is in place, we trust ourselves
// and if UserSignalHandler is installed all bets are off.
// Log that signal checking is off only if -verbose:jni is specified.
if (CheckJNICalls) {
if (libjsig_is_loaded) {
log_debug(jni, resolve)("Info: libjsig is activated, all active signal checking is disabled");
check_signals = false;
}
if (AllowUserSignalHandlers) {
log_debug(jni, resolve)("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled");
check_signals = false;
}
}
}
// Returns one-line short description of a signal set in a user provided buffer.
static const char* describe_signal_set_short(const sigset_t* set, char* buffer, size_t buf_size) {
assert(buf_size == (NUM_IMPORTANT_SIGS + 1), "wrong buffer size");
// Note: for shortness, just print out the first 32. That should
// cover most of the useful ones, apart from realtime signals.
for (int sig = 1; sig <= NUM_IMPORTANT_SIGS; sig++) {
const int rc = sigismember(set, sig);
if (rc == -1 && errno == EINVAL) {
buffer[sig-1] = '?';
} else {
buffer[sig-1] = rc == 0 ? '0' : '1';
}
}
buffer[NUM_IMPORTANT_SIGS] = 0;
return buffer;
}
// Prints one-line description of a signal set.
static void print_signal_set_short(outputStream* st, const sigset_t* set) {
char buf[NUM_IMPORTANT_SIGS + 1];
describe_signal_set_short(set, buf, sizeof(buf));
st->print("%s", buf);
}
static void print_single_signal_handler(outputStream* st,
const struct sigaction* act,
char* buf, size_t buflen) {
address handler = get_signal_handler(act);
if (HANDLER_IS_DFL(handler)) {
st->print("SIG_DFL");
} else if (HANDLER_IS_IGN(handler)) {
st->print("SIG_IGN");
} else {
print_signal_handler_name(st, handler, buf, buflen);
}
st->print(", mask=");
print_signal_set_short(st, &(act->sa_mask));
st->print(", flags=");
int flags = get_sanitized_sa_flags(act);
print_sa_flags(st, flags);
}
// Print established signal handler for this signal.
// - if this signal handler was installed by us and is chained to a pre-established user handler
// it replaced, print that one too.
// - otherwise, if this signal handler was installed by us and replaced another handler to which we
// are not chained (e.g. if chaining is off), print that one too.
void PosixSignals::print_signal_handler(outputStream* st, int sig,
char* buf, size_t buflen) {
st->print("%10s: ", os::exception_name(sig, buf, buflen));
struct sigaction current_act;
sigaction(sig, NULL, ¤t_act);
print_single_signal_handler(st, ¤t_act, buf, buflen);
sigset_t thread_sig_mask;
if (::pthread_sigmask(/* ignored */ SIG_BLOCK, NULL, &thread_sig_mask) == 0) {
st->print(", %s", sigismember(&thread_sig_mask, sig) ? "blocked" : "unblocked");
}
st->cr();
// If we expected to see our own hotspot signal handler but found a different one,
// print a warning (unless the handler replacing it is our own crash handler, which can
// happen if this function is called during error reporting).
const struct sigaction* expected_act = vm_handlers.get(sig);
if (expected_act != NULL) {
const address current_handler = get_signal_handler(¤t_act);
if (!(HANDLER_IS(current_handler, VMError::crash_handler_address))) {
if (!are_actions_equal(¤t_act, expected_act)) {
st->print_cr(" *** Handler was modified!");
st->print (" *** Expected: ");
print_single_signal_handler(st, expected_act, buf, buflen);
st->cr();
}
}
}
// If there is a chained handler waiting behind the current one, print it too.
const struct sigaction* chained_act = get_chained_signal_action(sig);
if (chained_act != NULL) {
st->print(" chained to: ");
print_single_signal_handler(st, ¤t_act, buf, buflen);
st->cr();
}
}
void os::print_signal_handlers(outputStream* st, char* buf, size_t buflen) {
st->print_cr("Signal Handlers:");
PosixSignals::print_signal_handler(st, SIGSEGV, buf, buflen);
PosixSignals::print_signal_handler(st, SIGBUS , buf, buflen);
PosixSignals::print_signal_handler(st, SIGFPE , buf, buflen);
PosixSignals::print_signal_handler(st, SIGPIPE, buf, buflen);
PosixSignals::print_signal_handler(st, SIGXFSZ, buf, buflen);
PosixSignals::print_signal_handler(st, SIGILL , buf, buflen);
PosixSignals::print_signal_handler(st, PosixSignals::SR_signum, buf, buflen);
PosixSignals::print_signal_handler(st, SHUTDOWN1_SIGNAL, buf, buflen);
PosixSignals::print_signal_handler(st, SHUTDOWN2_SIGNAL , buf, buflen);
PosixSignals::print_signal_handler(st, SHUTDOWN3_SIGNAL , buf, buflen);
PosixSignals::print_signal_handler(st, BREAK_SIGNAL, buf, buflen);
#if defined(SIGDANGER)
// We also want to know if someone else adds a SIGDANGER handler because
// that will interfere with OOM killling.
PosixSignals::print_signal_handler(st, SIGDANGER, buf, buflen);
#endif
#if defined(SIGTRAP)
PosixSignals::print_signal_handler(st, SIGTRAP, buf, buflen);
#endif
}
bool PosixSignals::is_sig_ignored(int sig) {
struct sigaction oact;
sigaction(sig, (struct sigaction*)NULL, &oact);
if (HANDLER_IS_IGN(get_signal_handler(&oact))) {
return true;
} else {
return false;
}
}
static void signal_sets_init() {
sigemptyset(&preinstalled_sigs);
// Should also have an assertion stating we are still single-threaded.
assert(!signal_sets_initialized, "Already initialized");
// Fill in signals that are necessarily unblocked for all threads in
// the VM. Currently, we unblock the following signals:
// SHUTDOWN{1,2,3}_SIGNAL: for shutdown hooks support (unless over-ridden
// by -Xrs (=ReduceSignalUsage));
// BREAK_SIGNAL which is unblocked only by the VM thread and blocked by all
// other threads. The "ReduceSignalUsage" boolean tells us not to alter
// the dispositions or masks wrt these signals.
// Programs embedding the VM that want to use the above signals for their
// own purposes must, at this time, use the "-Xrs" option to prevent
// interference with shutdown hooks and BREAK_SIGNAL thread dumping.
// (See bug 4345157, and other related bugs).
// In reality, though, unblocking these signals is really a nop, since
// these signals are not blocked by default.
sigemptyset(&unblocked_sigs);
sigaddset(&unblocked_sigs, SIGILL);
sigaddset(&unblocked_sigs, SIGSEGV);
sigaddset(&unblocked_sigs, SIGBUS);
sigaddset(&unblocked_sigs, SIGFPE);
PPC64_ONLY(sigaddset(&unblocked_sigs, SIGTRAP);)
sigaddset(&unblocked_sigs, PosixSignals::SR_signum);
if (!ReduceSignalUsage) {
if (!PosixSignals::is_sig_ignored(SHUTDOWN1_SIGNAL)) {
sigaddset(&unblocked_sigs, SHUTDOWN1_SIGNAL);
}
if (!PosixSignals::is_sig_ignored(SHUTDOWN2_SIGNAL)) {
sigaddset(&unblocked_sigs, SHUTDOWN2_SIGNAL);
}
if (!PosixSignals::is_sig_ignored(SHUTDOWN3_SIGNAL)) {
sigaddset(&unblocked_sigs, SHUTDOWN3_SIGNAL);
}
}
// Fill in signals that are blocked by all but the VM thread.
sigemptyset(&vm_sigs);
if (!ReduceSignalUsage) {
sigaddset(&vm_sigs, BREAK_SIGNAL);
}
debug_only(signal_sets_initialized = true);
}
// These are signals that are unblocked while a thread is running Java.
// (For some reason, they get blocked by default.)
static sigset_t* unblocked_signals() {
assert(signal_sets_initialized, "Not initialized");
return &unblocked_sigs;
}
// These are the signals that are blocked while a (non-VM) thread is
// running Java. Only the VM thread handles these signals.
static sigset_t* vm_signals() {
assert(signal_sets_initialized, "Not initialized");
return &vm_sigs;
}
void PosixSignals::hotspot_sigmask(Thread* thread) {
//Save caller's signal mask before setting VM signal mask
sigset_t caller_sigmask;
pthread_sigmask(SIG_BLOCK, NULL, &caller_sigmask);
OSThread* osthread = thread->osthread();
osthread->set_caller_sigmask(caller_sigmask);
pthread_sigmask(SIG_UNBLOCK, unblocked_signals(), NULL);
if (!ReduceSignalUsage) {
if (thread->is_VM_thread()) {
// Only the VM thread handles BREAK_SIGNAL ...
pthread_sigmask(SIG_UNBLOCK, vm_signals(), NULL);
} else {
// ... all other threads block BREAK_SIGNAL
pthread_sigmask(SIG_BLOCK, vm_signals(), NULL);
}
}
}
////////////////////////////////////////////////////////////////////////////////
// suspend/resume support
// The low-level signal-based suspend/resume support is a remnant from the
// old VM-suspension that used to be for java-suspension, safepoints etc,
// within hotspot. Currently used by JFR's OSThreadSampler
//
// The remaining code is greatly simplified from the more general suspension
// code that used to be used.
//
// The protocol is quite simple:
// - suspend:
// - sends a signal to the target thread
// - polls the suspend state of the osthread using a yield loop
// - target thread signal handler (SR_handler) sets suspend state
// and blocks in sigsuspend until continued
// - resume:
// - sets target osthread state to continue
// - sends signal to end the sigsuspend loop in the SR_handler
//
// Note that resume_clear_context() and suspend_save_context() are needed
// by SR_handler(), so that fetch_frame_from_context() works,
// which in part is used by:
// - Forte Analyzer: AsyncGetCallTrace()
// - StackBanging: get_frame_at_stack_banging_point()
static void resume_clear_context(OSThread *osthread) {
osthread->set_ucontext(NULL);
osthread->set_siginfo(NULL);
}
static void suspend_save_context(OSThread *osthread, siginfo_t* siginfo, void* ucVoid) {
osthread->set_ucontext((ucontext_t*)ucVoid);
osthread->set_siginfo(siginfo);
}
// Handler function invoked when a thread's execution is suspended or
// resumed. We have to be careful that only async-safe functions are
// called here (Note: most pthread functions are not async safe and
// should be avoided.)
//
// Note: sigwait() is a more natural fit than sigsuspend() from an
// interface point of view, but sigwait() prevents the signal handler
// from being run. libpthread would get very confused by not having
// its signal handlers run and prevents sigwait()'s use with the
// mutex granting signal.
//
// Currently only ever called on the VMThread and JavaThreads (PC sampling)
//
static void SR_handler(int sig, siginfo_t* siginfo, void* context) {
// Save and restore errno to avoid confusing native code with EINTR
// after sigsuspend.
int old_errno = errno;
PosixSignals::unblock_error_signals();
Thread* thread = Thread::current_or_null_safe();
// The suspend/resume signal may have been sent from outside the process, deliberately or
// accidentally. In that case the receiving thread may not be attached to the VM. We handle
// that case by asserting (debug VM) resp. writing a diagnostic message to tty and
// otherwise ignoring the stray signal (release VMs).
// We print the siginfo as part of the diagnostics, which also contains the sender pid of
// the stray signal.
if (thread == nullptr) {
stringStream ss;
ss.print_raw("Non-attached thread received stray SR signal (");
os::print_siginfo(&ss, siginfo);
ss.print_raw(").");
assert(thread != NULL, "%s.", ss.base());
log_warning(os)("%s", ss.base());
return;
}
// On some systems we have seen signal delivery get "stuck" until the signal
// mask is changed as part of thread termination. Check that the current thread
// has not already terminated - else the following assertion
// will fail because the thread is no longer a JavaThread as the ~JavaThread
// destructor has completed.
if (thread->has_terminated()) {
return;
}
assert(thread->is_VM_thread() || thread->is_Java_thread(), "Must be VMThread or JavaThread");
OSThread* osthread = thread->osthread();
SuspendResume::State current = osthread->sr.state();
if (current == SuspendResume::SR_SUSPEND_REQUEST) {
suspend_save_context(osthread, siginfo, context);
// attempt to switch the state, we assume we had a SUSPEND_REQUEST
SuspendResume::State state = osthread->sr.suspended();
if (state == SuspendResume::SR_SUSPENDED) {
sigset_t suspend_set; // signals for sigsuspend()
sigemptyset(&suspend_set);
// get current set of blocked signals and unblock resume signal
pthread_sigmask(SIG_BLOCK, NULL, &suspend_set);
sigdelset(&suspend_set, PosixSignals::SR_signum);
sr_semaphore.signal();
// wait here until we are resumed
while (1) {
sigsuspend(&suspend_set);
SuspendResume::State result = osthread->sr.running();
if (result == SuspendResume::SR_RUNNING) {
// double check AIX doesn't need this!
sr_semaphore.signal();
break;
} else if (result != SuspendResume::SR_SUSPENDED) {
ShouldNotReachHere();
}
}
} else if (state == SuspendResume::SR_RUNNING) {
// request was cancelled, continue
} else {
ShouldNotReachHere();
}
resume_clear_context(osthread);
} else if (current == SuspendResume::SR_RUNNING) {
// request was cancelled, continue
} else if (current == SuspendResume::SR_WAKEUP_REQUEST) {
// ignore
} else {
// ignore
}
errno = old_errno;
}
int SR_initialize() {
struct sigaction act;
char *s;
// Get signal number to use for suspend/resume
if ((s = ::getenv("_JAVA_SR_SIGNUM")) != 0) {
int sig = ::strtol(s, 0, 10);
if (sig > MAX2(SIGSEGV, SIGBUS) && // See 4355769.
sig < NSIG) { // Must be legal signal and fit into sigflags[].
PosixSignals::SR_signum = sig;
} else {
warning("You set _JAVA_SR_SIGNUM=%d. It must be in range [%d, %d]. Using %d instead.",
sig, MAX2(SIGSEGV, SIGBUS)+1, NSIG-1, PosixSignals::SR_signum);
}
}
assert(PosixSignals::SR_signum > SIGSEGV && PosixSignals::SR_signum > SIGBUS,
"SR_signum must be greater than max(SIGSEGV, SIGBUS), see 4355769");
// Set up signal handler for suspend/resume
act.sa_flags = SA_RESTART|SA_SIGINFO;
act.sa_sigaction = SR_handler;
// SR_signum is blocked when the handler runs.
pthread_sigmask(SIG_BLOCK, NULL, &act.sa_mask);
remove_error_signals_from_set(&(act.sa_mask));
if (sigaction(PosixSignals::SR_signum, &act, 0) == -1) {
return -1;
}
// Save signal setup information for later checking.
vm_handlers.set(PosixSignals::SR_signum, &act);
do_check_signal_periodically[PosixSignals::SR_signum] = true;
return 0;
}
static int sr_notify(OSThread* osthread) {
int status = pthread_kill(osthread->pthread_id(), PosixSignals::SR_signum);
assert_status(status == 0, status, "pthread_kill");
return status;
}
// returns true on success and false on error - really an error is fatal
// but this seems the normal response to library errors
bool PosixSignals::do_suspend(OSThread* osthread) {
assert(osthread->sr.is_running(), "thread should be running");
assert(!sr_semaphore.trywait(), "semaphore has invalid state");
// mark as suspended and send signal
if (osthread->sr.request_suspend() != SuspendResume::SR_SUSPEND_REQUEST) {
// failed to switch, state wasn't running?
ShouldNotReachHere();
return false;
}
if (sr_notify(osthread) != 0) {
ShouldNotReachHere();
}
// managed to send the signal and switch to SUSPEND_REQUEST, now wait for SUSPENDED
while (true) {
if (sr_semaphore.timedwait(2)) {
break;
} else {
// timeout
SuspendResume::State cancelled = osthread->sr.cancel_suspend();
if (cancelled == SuspendResume::SR_RUNNING) {
return false;
} else if (cancelled == SuspendResume::SR_SUSPENDED) {
// make sure that we consume the signal on the semaphore as well
sr_semaphore.wait();
break;
} else {
ShouldNotReachHere();
return false;
}
}
}
guarantee(osthread->sr.is_suspended(), "Must be suspended");
return true;
}
void PosixSignals::do_resume(OSThread* osthread) {
assert(osthread->sr.is_suspended(), "thread should be suspended");
assert(!sr_semaphore.trywait(), "invalid semaphore state");
if (osthread->sr.request_wakeup() != SuspendResume::SR_WAKEUP_REQUEST) {
// failed to switch to WAKEUP_REQUEST
ShouldNotReachHere();
return;
}
while (true) {
if (sr_notify(osthread) == 0) {
if (sr_semaphore.timedwait(2)) {
if (osthread->sr.is_running()) {
return;
}
}
} else {
ShouldNotReachHere();
}
}
guarantee(osthread->sr.is_running(), "Must be running!");
}
void SuspendedThreadTask::internal_do_task() {
if (PosixSignals::do_suspend(_thread->osthread())) {
SuspendedThreadTaskContext context(_thread, _thread->osthread()->ucontext());
do_task(context);
PosixSignals::do_resume(_thread->osthread());
}
}
int PosixSignals::init() {
// initialize suspend/resume support - must do this before signal_sets_init()
if (SR_initialize() != 0) {
vm_exit_during_initialization("SR_initialize failed");
return JNI_ERR;
}
signal_sets_init();
// Initialize data for jdk.internal.misc.Signal and BREAK_SIGNAL's handler.
if (!ReduceSignalUsage) {
jdk_misc_signal_init();
}
install_signal_handlers();
return JNI_OK;
}
¤ Dauer der Verarbeitung: 0.59 Sekunden
(vorverarbeitet)
¤
|
Haftungshinweis
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.
|