8254158: Consolidate per-platform stack overflow handling code

Reviewed-by: fparain, hseigel
This commit is contained in:
Coleen Phillimore 2020-10-13 20:42:34 +00:00
parent 715e24afb2
commit ba5dc67a74
10 changed files with 168 additions and 513 deletions

View file

@ -162,40 +162,11 @@ frame os::fetch_frame_from_context(const void* ucVoid) {
return frame(sp, epc);
}
bool os::Linux::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) {
address pc = (address) os::Linux::ucontext_get_pc(uc);
if (Interpreter::contains(pc)) {
// Interpreter performs stack banging after the fixed frame header has
// been generated while the compilers perform it before. To maintain
// semantic consistency between interpreted and compiled frames, the
// method returns the Java sender of the current frame.
*fr = os::fetch_frame_from_context(uc);
if (!fr->is_first_java_frame()) {
assert(fr->safe_for_sender(thread), "Safety check");
*fr = fr->java_sender();
}
} else {
// More complex code with compiled code.
assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
CodeBlob* cb = CodeCache::find_blob(pc);
if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
// Not sure where the pc points to, fallback to default
// stack overflow handling. In compiled code, we bang before
// the frame is complete.
return false;
} else {
intptr_t* sp = os::Linux::ucontext_get_sp(uc);
address lr = ucontext_get_lr(uc);
*fr = frame(sp, lr);
if (!fr->is_java_frame()) {
assert(fr->safe_for_sender(thread), "Safety check");
assert(!fr->is_first_frame(), "Safety check");
*fr = fr->java_sender();
}
}
}
assert(fr->is_java_frame(), "Safety check");
return true;
frame os::fetch_compiled_frame_from_context(const void* ucVoid) {
const ucontext_t* uc = (const ucontext_t*)ucVoid;
intptr_t* sp = os::Linux::ucontext_get_sp(uc);
address lr = ucontext_get_lr(uc);
return frame(sp, lr);
}
frame os::get_sender_for_C_frame(frame* fr) {
@ -327,60 +298,8 @@ JVM_handle_linux_signal(int sig,
// Check if fault address is within thread stack.
if (thread->is_in_full_stack(addr)) {
// stack overflow
StackOverflow* overflow_state = thread->stack_overflow_state();
if (overflow_state->in_stack_yellow_reserved_zone(addr)) {
if (thread->thread_state() == _thread_in_Java) {
if (overflow_state->in_stack_reserved_zone(addr)) {
frame fr;
if (os::Linux::get_frame_at_stack_banging_point(thread, uc, &fr)) {
assert(fr.is_java_frame(), "Must be a Javac frame");
frame activation =
SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
if (activation.sp() != NULL) {
overflow_state->disable_stack_reserved_zone();
if (activation.is_interpreted_frame()) {
overflow_state->set_reserved_stack_activation((address)activation.fp());
} else {
overflow_state->set_reserved_stack_activation((address)activation.unextended_sp());
}
return 1;
}
}
}
// Throw a stack overflow exception.
// Guard pages will be reenabled while unwinding the stack.
overflow_state->disable_stack_yellow_reserved_zone();
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
} else {
// Thread was in the vm or native code. Return and try to finish.
overflow_state->disable_stack_yellow_reserved_zone();
return 1;
}
} else if (overflow_state->in_stack_red_zone(addr)) {
// Fatal red zone violation. Disable the guard pages and fall through
// to handle_unexpected_exception way down below.
overflow_state->disable_stack_red_zone();
tty->print_raw_cr("An irrecoverable stack overflow has occurred.");
// This is a likely cause, but hard to verify. Let's just print
// it as a hint.
tty->print_raw_cr("Please check if any of your loaded .so files has "
"enabled executable stack (see man page execstack(8))");
} else {
// Accessing stack address below sp may cause SEGV if current
// thread has MAP_GROWSDOWN stack. This should only happen when
// current thread was created by user code with MAP_GROWSDOWN flag
// and then attached to VM. See notes in os_linux.cpp.
if (thread->osthread()->expanding_stack() == 0) {
thread->osthread()->set_expanding_stack();
if (os::Linux::manually_expand_stack(thread, addr)) {
thread->osthread()->clear_expanding_stack();
return 1;
}
thread->osthread()->clear_expanding_stack();
} else {
fatal("recursive segv. expanding stack.");
}
if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) {
return 1; // continue
}
}
}