Skip to content

Commit ba5dc67

Browse files
committed
8254158: Consolidate per-platform stack overflow handling code
Reviewed-by: fparain, hseigel
1 parent 715e24a commit ba5dc67

File tree

10 files changed

+168
-513
lines changed

10 files changed

+168
-513
lines changed

src/hotspot/os/linux/os_linux.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,6 @@ class Linux {
139139
static intptr_t* ucontext_get_sp(const ucontext_t* uc);
140140
static intptr_t* ucontext_get_fp(const ucontext_t* uc);
141141

142-
static bool get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr);
143-
144142
// GNU libc and libpthread version strings
145143
static const char *libc_version() { return _libc_version; }
146144
static const char *libpthread_version() { return _libpthread_version; }

src/hotspot/os/posix/os_posix.cpp

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "utilities/globalDefinitions.hpp"
3131
#include "runtime/frame.inline.hpp"
3232
#include "runtime/interfaceSupport.inline.hpp"
33+
#include "runtime/sharedRuntime.hpp"
3334
#include "services/memTracker.hpp"
3435
#include "runtime/atomic.hpp"
3536
#include "runtime/java.hpp"
@@ -907,6 +908,119 @@ size_t os::Posix::get_initial_stack_size(ThreadType thr_type, size_t req_stack_s
907908
return stack_size;
908909
}
909910

911+
#ifndef ZERO
912+
#ifndef ARM
913+
static bool get_frame_at_stack_banging_point(JavaThread* thread, address pc, const void* ucVoid, frame* fr) {
914+
if (Interpreter::contains(pc)) {
915+
// interpreter performs stack banging after the fixed frame header has
916+
// been generated while the compilers perform it before. To maintain
917+
// semantic consistency between interpreted and compiled frames, the
918+
// method returns the Java sender of the current frame.
919+
*fr = os::fetch_frame_from_context(ucVoid);
920+
if (!fr->is_first_java_frame()) {
921+
// get_frame_at_stack_banging_point() is only called when we
922+
// have well defined stacks so java_sender() calls do not need
923+
// to assert safe_for_sender() first.
924+
*fr = fr->java_sender();
925+
}
926+
} else {
927+
// more complex code with compiled code
928+
assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
929+
CodeBlob* cb = CodeCache::find_blob(pc);
930+
if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
931+
// Not sure where the pc points to, fallback to default
932+
// stack overflow handling
933+
return false;
934+
} else {
935+
// in compiled code, the stack banging is performed just after the return pc
936+
// has been pushed on the stack
937+
*fr = os::fetch_compiled_frame_from_context(ucVoid);
938+
if (!fr->is_java_frame()) {
939+
assert(!fr->is_first_frame(), "Safety check");
940+
// See java_sender() comment above.
941+
*fr = fr->java_sender();
942+
}
943+
}
944+
}
945+
assert(fr->is_java_frame(), "Safety check");
946+
return true;
947+
}
948+
#endif // ARM
949+
950+
// This return true if the signal handler should just continue, ie. return after calling this
951+
bool os::Posix::handle_stack_overflow(JavaThread* thread, address addr, address pc,
952+
const void* ucVoid, address* stub) {
953+
// stack overflow
954+
StackOverflow* overflow_state = thread->stack_overflow_state();
955+
if (overflow_state->in_stack_yellow_reserved_zone(addr)) {
956+
if (thread->thread_state() == _thread_in_Java) {
957+
#ifndef ARM
958+
// arm32 doesn't have this
959+
if (overflow_state->in_stack_reserved_zone(addr)) {
960+
frame fr;
961+
if (get_frame_at_stack_banging_point(thread, pc, ucVoid, &fr)) {
962+
assert(fr.is_java_frame(), "Must be a Java frame");
963+
frame activation =
964+
SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
965+
if (activation.sp() != NULL) {
966+
overflow_state->disable_stack_reserved_zone();
967+
if (activation.is_interpreted_frame()) {
968+
overflow_state->set_reserved_stack_activation((address)(
969+
activation.fp() + frame::interpreter_frame_initial_sp_offset));
970+
} else {
971+
overflow_state->set_reserved_stack_activation((address)activation.unextended_sp());
972+
}
973+
return true; // just continue
974+
}
975+
}
976+
}
977+
#endif // ARM
978+
// Throw a stack overflow exception. Guard pages will be reenabled
979+
// while unwinding the stack.
980+
overflow_state->disable_stack_yellow_reserved_zone();
981+
*stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
982+
} else {
983+
// Thread was in the vm or native code. Return and try to finish.
984+
overflow_state->disable_stack_yellow_reserved_zone();
985+
return true; // just continue
986+
}
987+
} else if (overflow_state->in_stack_red_zone(addr)) {
988+
// Fatal red zone violation. Disable the guard pages and fall through
989+
// to handle_unexpected_exception way down below.
990+
overflow_state->disable_stack_red_zone();
991+
tty->print_raw_cr("An irrecoverable stack overflow has occurred.");
992+
993+
// This is a likely cause, but hard to verify. Let's just print
994+
// it as a hint.
995+
tty->print_raw_cr("Please check if any of your loaded .so files has "
996+
"enabled executable stack (see man page execstack(8))");
997+
998+
} else {
999+
#if !defined(AIX) && !defined(__APPLE__)
1000+
// bsd and aix don't have this
1001+
1002+
// Accessing stack address below sp may cause SEGV if current
1003+
// thread has MAP_GROWSDOWN stack. This should only happen when
1004+
// current thread was created by user code with MAP_GROWSDOWN flag
1005+
// and then attached to VM. See notes in os_linux.cpp.
1006+
if (thread->osthread()->expanding_stack() == 0) {
1007+
thread->osthread()->set_expanding_stack();
1008+
if (os::Linux::manually_expand_stack(thread, addr)) {
1009+
thread->osthread()->clear_expanding_stack();
1010+
return true; // just continue
1011+
}
1012+
thread->osthread()->clear_expanding_stack();
1013+
} else {
1014+
fatal("recursive segv. expanding stack.");
1015+
}
1016+
#else
1017+
tty->print_raw_cr("SIGSEGV happened inside stack but outside yellow and red zone.");
1018+
#endif // AIX or BSD
1019+
}
1020+
return false;
1021+
}
1022+
#endif // ZERO
1023+
9101024
bool os::Posix::is_root(uid_t uid){
9111025
return ROOT_UID == uid;
9121026
}

src/hotspot/os/posix/os_posix.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ class Posix {
106106
#endif
107107

108108
static void to_RTC_abstime(timespec* abstime, int64_t millis);
109+
110+
static bool handle_stack_overflow(JavaThread* thread, address addr, address pc,
111+
const void* ucVoid,
112+
address* stub);
109113
};
110114

111115
/*

src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp

Lines changed: 9 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -142,40 +142,11 @@ frame os::fetch_frame_from_context(const void* ucVoid) {
142142
return fr;
143143
}
144144

145-
bool os::Aix::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) {
146-
address pc = (address) os::Aix::ucontext_get_pc(uc);
147-
if (Interpreter::contains(pc)) {
148-
// Interpreter performs stack banging after the fixed frame header has
149-
// been generated while the compilers perform it before. To maintain
150-
// semantic consistency between interpreted and compiled frames, the
151-
// method returns the Java sender of the current frame.
152-
*fr = os::fetch_frame_from_context(uc);
153-
if (!fr->is_first_java_frame()) {
154-
assert(fr->safe_for_sender(thread), "Safety check");
155-
*fr = fr->java_sender();
156-
}
157-
} else {
158-
// More complex code with compiled code.
159-
assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
160-
CodeBlob* cb = CodeCache::find_blob(pc);
161-
if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
162-
// Not sure where the pc points to, fallback to default
163-
// stack overflow handling. In compiled code, we bang before
164-
// the frame is complete.
165-
return false;
166-
} else {
167-
intptr_t* sp = os::Aix::ucontext_get_sp(uc);
168-
address lr = ucontext_get_lr(uc);
169-
*fr = frame(sp, lr);
170-
if (!fr->is_java_frame()) {
171-
assert(fr->safe_for_sender(thread), "Safety check");
172-
assert(!fr->is_first_frame(), "Safety check");
173-
*fr = fr->java_sender();
174-
}
175-
}
176-
}
177-
assert(fr->is_java_frame(), "Safety check");
178-
return true;
145+
frame os::fetch_compiled_frame_from_context(const void* ucVoid) {
146+
const ucontext_t* uc = (const ucontext_t*)ucVoid;
147+
intptr_t* sp = os::Aix::ucontext_get_sp(uc);
148+
address lr = ucontext_get_lr(uc);
149+
*fr = frame(sp, lr);
179150
}
180151

181152
frame os::get_sender_for_C_frame(frame* fr) {
@@ -267,56 +238,13 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
267238
// Handle ALL stack overflow variations here
268239
if (sig == SIGSEGV && thread->is_in_full_stack(addr)) {
269240
// stack overflow
270-
StackOverflow* overflow_state = thread->stack_overflow_state();
271-
272-
//
273-
// If we are in a yellow zone and we are inside java, we disable the yellow zone and
274-
// throw a stack overflow exception.
275-
// If we are in native code or VM C code, we report-and-die. The original coding tried
276-
// to continue with yellow zone disabled, but that doesn't buy us much and prevents
277-
// hs_err_pid files.
278-
if (overflow_state->in_stack_yellow_reserved_zone(addr)) {
279-
if (thread->thread_state() == _thread_in_Java) {
280-
if (overflow_state->in_stack_reserved_zone(addr)) {
281-
frame fr;
282-
if (os::Aix::get_frame_at_stack_banging_point(thread, uc, &fr)) {
283-
assert(fr.is_java_frame(), "Must be a Javac frame");
284-
frame activation =
285-
SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
286-
if (activation.sp() != NULL) {
287-
overflow_state->disable_stack_reserved_zone();
288-
if (activation.is_interpreted_frame()) {
289-
overflow_state->set_reserved_stack_activation((address)activation.fp());
290-
} else {
291-
overflow_state->set_reserved_stack_activation((address)activation.unextended_sp());
292-
}
293-
return 1;
294-
}
295-
}
296-
}
297-
// Throw a stack overflow exception.
298-
// Guard pages will be reenabled while unwinding the stack.
299-
overflow_state->disable_stack_yellow_reserved_zone();
300-
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
301-
goto run_stub;
302-
} else {
303-
// Thread was in the vm or native code. Return and try to finish.
304-
overflow_state->disable_stack_yellow_reserved_zone();
305-
return 1;
306-
}
307-
} else if (overflow_state->in_stack_red_zone(addr)) {
308-
// Fatal red zone violation. Disable the guard pages and fall through
309-
// to handle_unexpected_exception way down below.
310-
overflow_state->disable_stack_red_zone();
311-
tty->print_raw_cr("An irrecoverable stack overflow has occurred.");
312-
goto report_and_die;
241+
if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) {
242+
return 1; // continue
243+
} else if (stub != NULL) {
244+
goto run_stub;
313245
} else {
314-
// This means a segv happened inside our stack, but not in
315-
// the guarded zone. I'd like to know when this happens,
316-
tty->print_raw_cr("SIGSEGV happened inside stack but outside yellow and red zone.");
317246
goto report_and_die;
318247
}
319-
320248
} // end handle SIGSEGV inside stack boundaries
321249

322250
if (thread->thread_state() == _thread_in_Java) {

src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp

Lines changed: 8 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -339,41 +339,12 @@ frame os::fetch_frame_from_context(const void* ucVoid) {
339339
return frame(sp, fp, epc);
340340
}
341341

342-
bool os::Bsd::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) {
343-
address pc = (address) os::Bsd::ucontext_get_pc(uc);
344-
if (Interpreter::contains(pc)) {
345-
// interpreter performs stack banging after the fixed frame header has
346-
// been generated while the compilers perform it before. To maintain
347-
// semantic consistency between interpreted and compiled frames, the
348-
// method returns the Java sender of the current frame.
349-
*fr = os::fetch_frame_from_context(uc);
350-
if (!fr->is_first_java_frame()) {
351-
// get_frame_at_stack_banging_point() is only called when we
352-
// have well defined stacks so java_sender() calls do not need
353-
// to assert safe_for_sender() first.
354-
*fr = fr->java_sender();
355-
}
356-
} else {
357-
// more complex code with compiled code
358-
assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
359-
CodeBlob* cb = CodeCache::find_blob(pc);
360-
if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
361-
// Not sure where the pc points to, fallback to default
362-
// stack overflow handling
363-
return false;
364-
} else {
365-
*fr = os::fetch_frame_from_context(uc);
366-
// in compiled code, the stack banging is performed just after the return pc
367-
// has been pushed on the stack
368-
*fr = frame(fr->sp() + 1, fr->fp(), (address)*(fr->sp()));
369-
if (!fr->is_java_frame()) {
370-
// See java_sender() comment above.
371-
*fr = fr->java_sender();
372-
}
373-
}
374-
}
375-
assert(fr->is_java_frame(), "Safety check");
376-
return true;
342+
frame os::fetch_compiled_frame_from_context(const void* ucVoid) {
343+
const ucontext_t* uc = (const ucontext_t*)ucVoid;
344+
frame fr = os::fetch_frame_from_context(uc);
345+
// in compiled code, the stack banging is performed just after the return pc
346+
// has been pushed on the stack
347+
return frame(fr.sp() + 1, fr.fp(), (address)*(fr.sp()));
377348
}
378349

379350
// By default, gcc always save frame pointer (%ebp/%rbp) on stack. It may get
@@ -495,40 +466,8 @@ JVM_handle_bsd_signal(int sig,
495466
// check if fault address is within thread stack
496467
if (thread->is_in_full_stack(addr)) {
497468
// stack overflow
498-
StackOverflow* overflow_state = thread->stack_overflow_state();
499-
if (overflow_state->in_stack_yellow_reserved_zone(addr)) {
500-
if (thread->thread_state() == _thread_in_Java) {
501-
if (overflow_state->in_stack_reserved_zone(addr)) {
502-
frame fr;
503-
if (os::Bsd::get_frame_at_stack_banging_point(thread, uc, &fr)) {
504-
assert(fr.is_java_frame(), "Must be a Java frame");
505-
frame activation = SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
506-
if (activation.sp() != NULL) {
507-
overflow_state->disable_stack_reserved_zone();
508-
if (activation.is_interpreted_frame()) {
509-
overflow_state->set_reserved_stack_activation((address)(
510-
activation.fp() + frame::interpreter_frame_initial_sp_offset));
511-
} else {
512-
overflow_state->set_reserved_stack_activation((address)activation.unextended_sp());
513-
}
514-
return 1;
515-
}
516-
}
517-
}
518-
// Throw a stack overflow exception. Guard pages will be reenabled
519-
// while unwinding the stack.
520-
overflow_state->disable_stack_yellow_reserved_zone();
521-
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
522-
} else {
523-
// Thread was in the vm or native code. Return and try to finish.
524-
overflow_state->disable_stack_yellow_reserved_zone();
525-
return 1;
526-
}
527-
} else if (overflow_state->in_stack_red_zone(addr)) {
528-
// Fatal red zone violation. Disable the guard pages and fall through
529-
// to handle_unexpected_exception way down below.
530-
overflow_state->disable_stack_red_zone();
531-
tty->print_raw_cr("An irrecoverable stack overflow has occurred.");
469+
if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) {
470+
return 1; // continue
532471
}
533472
}
534473
}

0 commit comments

Comments
 (0)