В Linux одно (возможно, из некоторых других) использование зон red и yellow_reserved - заставить JVM HotSpot обрабатывать переполнение стека. На pthreads_attr_setguardsize
странице справки есть примечание об установке размера защиты на 0:
ответственность за переполнение стека лежит на приложении
(возможно, используя mprotect(2)
, чтобы вручную определить охранную зону на
конец выделенного им стека).
и
Установка размера защиты 0 может быть полезна для сохранения памяти в
приложение, которое создает много потоков и знает, что переполнение стека
никогда не может произойти.
Таким образом, поскольку никакие потоки (даже первичные) не используют отображение MAP_GROWSDOWN
для своего стека, устанавливая размер защиты в 0 в этой точке , вероятно, можно рассматривать как оптимизацию. «Переполнение стека никогда не происходит» гарантируется страницами reserved
/ yellow
/ red
, которые JVM вручную отображает в функции void JavaThread::create_stack_guard_pages()
.
Как видно, некоторая часть внизу стека потока даже без защитных страниц pthread
обрабатывается как HotSpot Guard Pages , то есть охраняется с mprotect
Правильно, как указала нам страница руководства.
Фактическая обработка переполнения стека выполняется с помощью обработчика сигнала , который устанавливается при запуске JVM. Часть, связанная с переполнением стека, выглядит так (немного длиннее):
// Handle ALL stack overflow variations here
if (sig == SIGSEGV) {
address addr = (address) info->si_addr;
// check if fault address is within thread stack
if (thread->on_local_stack(addr)) {
// stack overflow
if (thread->in_stack_yellow_reserved_zone(addr)) {
if (thread->thread_state() == _thread_in_Java) {
if (thread->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 Java frame");
frame activation =
SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
if (activation.sp() != NULL) {
thread->disable_stack_reserved_zone();
if (activation.is_interpreted_frame()) {
thread->set_reserved_stack_activation((address)(
activation.fp() + frame::interpreter_frame_initial_sp_offset));
} else {
thread->set_reserved_stack_activation((address)activation.unextended_sp());
}
return 1;
}
}
}
// Throw a stack overflow exception. Guard pages will be reenabled
// while unwinding the stack.
thread->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.
thread->disable_stack_yellow_reserved_zone();
return 1;
}
} else if (thread->in_stack_red_zone(addr)) {
// Fatal red zone violation. Disable the guard pages and fall through
// to handle_unexpected_exception way down below.
thread->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 {
//...
Как видно из кода. Если SIGSEGV
поднимается, когда в зарезервированной или желтой зоне защитные страницы не охраняются, ошибка StackOverflowError
отправляется в Java, и защита снова включается при разматывании стека.
В отличие от этого, если SIGSEGV
поднимается, когда в красной зоне он рассматривается как "неисправимая ошибка переполнения стека".
Например:
public class Main {
static void foo() throws Exception {
foo();
}
public static void main(String args[]) throws Exception {
foo();
}
}
как можно заметить с gdb
, это StackOverflowError
произошло в зарезервированной / желтой зоне, а не в красной (поэтому, вероятно, это причина того, что это может быть обработано обработчиком try
- catch
).
В заключение следует отметить, что красная зона охранника HotSpot имеет совершенно другое значение, чем AMD64 System V ABI определение красной зоны (просто область, в которую вызывающий абонент может поместить локальные переменные, чтобы они не были затронуты сигналом / прерыванием обработчик или, возможно, отладчик, поскольку gdb
может поместить свои собственные данные в стек за пределами красной зоны).