Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions hotspot/src/os/aix/vm/vmError_aix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ static void save_signal(int idx, int sig) {
}

int VMError::get_resetted_sigflags(int sig) {
// Handle all program errors.
for (int i = 0; i < NUM_SIGNALS; i++) {
if (SIGNALS[i] == sig) {
return resettedSigflags[i];
Expand All @@ -90,7 +89,6 @@ int VMError::get_resetted_sigflags(int sig) {
}

address VMError::get_resetted_sighandler(int sig) {
// Handle all program errors.
for (int i = 0; i < NUM_SIGNALS; i++) {
if (SIGNALS[i] == sig) {
return resettedSighandler[i];
Expand All @@ -100,12 +98,19 @@ address VMError::get_resetted_sighandler(int sig) {
}

static void crash_handler(int sig, siginfo_t* info, void* ucVoid) {

// Unmask current signal.
sigset_t newset;
sigemptyset(&newset);
sigaddset(&newset, sig);
// and all other synchronous signals too.
for (int i = 0; i < NUM_SIGNALS; i++) {
sigaddset(&newset, SIGNALS[i]);
}
sigthreadmask(SIG_UNBLOCK, &newset, NULL);

Unimplemented();
VMError err(NULL, sig, NULL, info, ucVoid);
err.report_and_die();
}

void VMError::reset_signal_handlers() {
Expand Down
47 changes: 31 additions & 16 deletions hotspot/src/os/bsd/vm/vmError_bsd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,15 @@ void VMError::show_message_box(char *buf, int buflen) {
} while (yes);
}

// handle all synchronous program error signals which may happen during error
// reporting. They must be unblocked, caught, handled.

static const int SIGNALS[] = { SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP }; // add more if needed
static const int NUM_SIGNALS = sizeof(SIGNALS) / sizeof(int);

// Space for our "saved" signal flags and handlers
static int resettedSigflags[2];
static address resettedSighandler[2];
static int resettedSigflags[NUM_SIGNALS];
static address resettedSighandler[NUM_SIGNALS];

static void save_signal(int idx, int sig)
{
Expand All @@ -78,19 +84,19 @@ static void save_signal(int idx, int sig)
}

int VMError::get_resetted_sigflags(int sig) {
if(SIGSEGV == sig) {
return resettedSigflags[0];
} else if(SIGBUS == sig) {
return resettedSigflags[1];
for (int i = 0; i < NUM_SIGNALS; i++) {
if (SIGNALS[i] == sig) {
return resettedSigflags[i];
}
}
return -1;
}

address VMError::get_resetted_sighandler(int sig) {
if(SIGSEGV == sig) {
return resettedSighandler[0];
} else if(SIGBUS == sig) {
return resettedSighandler[1];
for (int i = 0; i < NUM_SIGNALS; i++) {
if (SIGNALS[i] == sig) {
return resettedSighandler[i];
}
}
return NULL;
}
Expand All @@ -100,16 +106,25 @@ static void crash_handler(int sig, siginfo_t* info, void* ucVoid) {
sigset_t newset;
sigemptyset(&newset);
sigaddset(&newset, sig);
sigprocmask(SIG_UNBLOCK, &newset, NULL);
// also unmask other synchronous signals
for (int i = 0; i < NUM_SIGNALS; i++) {
sigaddset(&newset, SIGNALS[i]);
}
pthread_sigmask(SIG_UNBLOCK, &newset, NULL);

VMError err(NULL, sig, NULL, info, ucVoid);
err.report_and_die();
}

void VMError::reset_signal_handlers() {
// Save sigflags for resetted signals
save_signal(0, SIGSEGV);
save_signal(1, SIGBUS);
os::signal(SIGSEGV, CAST_FROM_FN_PTR(void *, crash_handler));
os::signal(SIGBUS, CAST_FROM_FN_PTR(void *, crash_handler));
// install signal handlers for all synchronous program error signals
sigset_t newset;
sigemptyset(&newset);

for (int i = 0; i < NUM_SIGNALS; i++) {
save_signal(i, SIGNALS[i]);
os::signal(SIGNALS[i], CAST_FROM_FN_PTR(void *, crash_handler));
sigaddset(&newset, SIGNALS[i]);
}
pthread_sigmask(SIG_UNBLOCK, &newset, NULL);
}
48 changes: 32 additions & 16 deletions hotspot/src/os/linux/vm/vmError_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,15 @@ void VMError::show_message_box(char *buf, int buflen) {
} while (yes);
}

// handle all synchronous program error signals which may happen during error
// reporting. They must be unblocked, caught, handled.

static const int SIGNALS[] = { SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP }; // add more if needed
static const int NUM_SIGNALS = sizeof(SIGNALS) / sizeof(int);

// Space for our "saved" signal flags and handlers
static int resettedSigflags[2];
static address resettedSighandler[2];
static int resettedSigflags[NUM_SIGNALS];
static address resettedSighandler[NUM_SIGNALS];

static void save_signal(int idx, int sig)
{
Expand All @@ -78,19 +84,19 @@ static void save_signal(int idx, int sig)
}

int VMError::get_resetted_sigflags(int sig) {
if(SIGSEGV == sig) {
return resettedSigflags[0];
} else if(SIGBUS == sig) {
return resettedSigflags[1];
for (int i = 0; i < NUM_SIGNALS; i++) {
if (SIGNALS[i] == sig) {
return resettedSigflags[i];
}
}
return -1;
}

address VMError::get_resetted_sighandler(int sig) {
if(SIGSEGV == sig) {
return resettedSighandler[0];
} else if(SIGBUS == sig) {
return resettedSighandler[1];
for (int i = 0; i < NUM_SIGNALS; i++) {
if (SIGNALS[i] == sig) {
return resettedSighandler[i];
}
}
return NULL;
}
Expand All @@ -100,16 +106,26 @@ static void crash_handler(int sig, siginfo_t* info, void* ucVoid) {
sigset_t newset;
sigemptyset(&newset);
sigaddset(&newset, sig);
sigprocmask(SIG_UNBLOCK, &newset, NULL);
// also unmask other synchronous signals
for (int i = 0; i < NUM_SIGNALS; i++) {
sigaddset(&newset, SIGNALS[i]);
}
pthread_sigmask(SIG_UNBLOCK, &newset, NULL);

VMError err(NULL, sig, NULL, info, ucVoid);
err.report_and_die();
}

void VMError::reset_signal_handlers() {
// Save sigflags for resetted signals
save_signal(0, SIGSEGV);
save_signal(1, SIGBUS);
os::signal(SIGSEGV, CAST_FROM_FN_PTR(void *, crash_handler));
os::signal(SIGBUS, CAST_FROM_FN_PTR(void *, crash_handler));
// install signal handlers for all synchronous program error signals
sigset_t newset;
sigemptyset(&newset);

for (int i = 0; i < NUM_SIGNALS; i++) {
save_signal(i, SIGNALS[i]);
os::signal(SIGNALS[i], CAST_FROM_FN_PTR(void *, crash_handler));
sigaddset(&newset, SIGNALS[i]);
}
pthread_sigmask(SIG_UNBLOCK, &newset, NULL);

}
48 changes: 32 additions & 16 deletions hotspot/src/os/solaris/vm/vmError_solaris.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include <sys/types.h>
#include <sys/wait.h>
#include <thread.h>
#include <signal.h>

void VMError::show_message_box(char *buf, int buflen) {
Expand Down Expand Up @@ -59,9 +60,15 @@ void VMError::show_message_box(char *buf, int buflen) {
} while (yes);
}

// handle all synchronous program error signals which may happen during error
// reporting. They must be unblocked, caught, handled.

static const int SIGNALS[] = { SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP }; // add more if needed
static const int NUM_SIGNALS = sizeof(SIGNALS) / sizeof(int);

// Space for our "saved" signal flags and handlers
static int resettedSigflags[2];
static address resettedSighandler[2];
static int resettedSigflags[NUM_SIGNALS];
static address resettedSighandler[NUM_SIGNALS];

static void save_signal(int idx, int sig)
{
Expand All @@ -74,19 +81,19 @@ static void save_signal(int idx, int sig)
}

int VMError::get_resetted_sigflags(int sig) {
if(SIGSEGV == sig) {
return resettedSigflags[0];
} else if(SIGBUS == sig) {
return resettedSigflags[1];
for (int i = 0; i < NUM_SIGNALS; i++) {
if (SIGNALS[i] == sig) {
return resettedSigflags[i];
}
}
return -1;
}

address VMError::get_resetted_sighandler(int sig) {
if(SIGSEGV == sig) {
return resettedSighandler[0];
} else if(SIGBUS == sig) {
return resettedSighandler[1];
for (int i = 0; i < NUM_SIGNALS; i++) {
if (SIGNALS[i] == sig) {
return resettedSighandler[i];
}
}
return NULL;
}
Expand All @@ -96,16 +103,25 @@ static void crash_handler(int sig, siginfo_t* info, void* ucVoid) {
sigset_t newset;
sigemptyset(&newset);
sigaddset(&newset, sig);
sigprocmask(SIG_UNBLOCK, &newset, NULL);
// also unmask other synchronous signals
for (int i = 0; i < NUM_SIGNALS; i++) {
sigaddset(&newset, SIGNALS[i]);
}
thr_sigsetmask(SIG_UNBLOCK, &newset, NULL);

VMError err(NULL, sig, NULL, info, ucVoid);
err.report_and_die();
}

void VMError::reset_signal_handlers() {
// Save sigflags for resetted signals
save_signal(0, SIGSEGV);
save_signal(1, SIGBUS);
os::signal(SIGSEGV, CAST_FROM_FN_PTR(void *, crash_handler));
os::signal(SIGBUS, CAST_FROM_FN_PTR(void *, crash_handler));
// install signal handlers for all synchronous program error signals
sigset_t newset;
sigemptyset(&newset);

for (int i = 0; i < NUM_SIGNALS; i++) {
save_signal(i, SIGNALS[i]);
os::signal(SIGNALS[i], CAST_FROM_FN_PTR(void *, crash_handler));
sigaddset(&newset, SIGNALS[i]);
}
thr_sigsetmask(SIG_UNBLOCK, &newset, NULL);
}
4 changes: 4 additions & 0 deletions hotspot/src/share/vm/runtime/globals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,10 @@ class CommandLineFlags {
"determines which error to provoke. See test_error_handler() " \
"in debug.cpp.") \
\
notproduct(uintx, TestCrashInErrorHandler, 0, \
"If > 0, provokes an error inside VM error handler (a secondary " \
"crash). see test_error_handler() in debug.cpp.") \
\
develop(bool, Verbose, false, \
"Print additional debugging information from other modes") \
\
Expand Down
48 changes: 42 additions & 6 deletions hotspot/src/share/vm/utilities/debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,13 +337,47 @@ bool is_error_reported() {
#ifndef PRODUCT
#include <signal.h>

typedef void (*voidfun_t)();
// Crash with an authentic sigfpe
static void crash_with_sigfpe() {
// generate a native synchronous SIGFPE where possible;
// if that did not cause a signal (e.g. on ppc), just
// raise the signal.
volatile int x = 0;
volatile int y = 1/x;
#ifndef _WIN32
raise(SIGFPE);
#endif
} // end: crash_with_sigfpe

// crash with sigsegv at non-null address.
static void crash_with_segfault() {

char* const crash_addr = (char*) get_segfault_address();
*crash_addr = 'X';

} // end: crash_with_segfault

// returns an address which is guaranteed to generate a SIGSEGV on read,
// for test purposes, which is not NULL and contains bits in every word
void* get_segfault_address() {
return (void*)
#ifdef _LP64
0xABC0000000000ABCULL;
#else
0x00000ABC;
#endif
}

void test_error_handler() {
uintx test_num = ErrorHandlerTest;
if (test_num == 0) return;
controlled_crash(ErrorHandlerTest);
}

void controlled_crash(int how) {
if (how == 0) return;

// If asserts are disabled, use the corresponding guarantee instead.
size_t n = test_num;
NOT_DEBUG(if (n <= 2) n += 2);
NOT_DEBUG(if (how <= 2) how += 2);

const char* const str = "hello";
const size_t num = (size_t)os::vm_page_size();
Expand All @@ -354,7 +388,7 @@ void test_error_handler() {
const void (*funcPtr)(void) = (const void(*)()) 0xF; // bad function pointer

// Keep this in sync with test/runtime/6888954/vmerrors.sh.
switch (n) {
switch (how) {
case 1: assert(str == NULL, "expected null");
case 2: assert(num == 1023 && *str == 'X',
err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str));
Expand All @@ -379,8 +413,10 @@ void test_error_handler() {
// There's no guarantee the bad function pointer will crash us
// so "break" out to the ShouldNotReachHere().
case 13: (*funcPtr)(); break;
case 14: crash_with_segfault(); break;
case 15: crash_with_sigfpe(); break;

default: tty->print_cr("ERROR: %d: unexpected test_num value.", n);
default: tty->print_cr("ERROR: %d: unexpected test_num value.", how);
}
ShouldNotReachHere();
}
Expand Down
18 changes: 18 additions & 0 deletions hotspot/src/share/vm/utilities/debug.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,24 @@ void set_error_reported();
/* Test assert(), fatal(), guarantee(), etc. */
NOT_PRODUCT(void test_error_handler();)

// crash in a controlled way:
// how can be one of:
// 1,2 - asserts
// 3,4 - guarantee
// 5-7 - fatal
// 8 - vm_exit_out_of_memory
// 9 - ShouldNotCallThis
// 10 - ShouldNotReachHere
// 11 - Unimplemented
// 12,13 - (not guaranteed) crashes
// 14 - SIGSEGV
// 15 - SIGFPE
NOT_PRODUCT(void controlled_crash(int how);)

// returns an address which is guaranteed to generate a SIGSEGV on read,
// for test purposes, which is not NULL and contains bits in every word
NOT_PRODUCT(void* get_segfault_address();)

void pd_ps(frame f);
void pd_obfuscate_location(char *buf, size_t buflen);

Expand Down
Loading