Исключение SEH StackOverflow — это реально невозможно поймать?

Я прочитал много статей о SEH exceptions в StackOverflow и CodeProject.net.

После того, как я реализовал SEH exceptions При обработке в моей C ++ программе на меня повлияло исключение переполнения стека, которое не было обнаружено моим программным обеспечением.

После следующей части исследования я понимаю, что программно невозможно обнаружить такое исключение, потому что у нас нет свободного адресного пространства стека, поэтому память программы повреждена.

Я хотел бы спросить вас о вашем опыте обработки исключения переполнения стека. Это выглядит как вызов, и мне действительно интересно, если это невозможно в языках программирования неуправляемого кода?

Ниже я представляю часть моей программы (C ++), которая воспроизводит stack overflow exception, Это прекрасно работает для любого SEH exception, но не переполнение стека:

LONG WINAPI SehHandler(PEXCEPTION_POINTERS pExceptionPtrs)
{
cerr << "Handled SEH exception!\n";
cerr << "ContextRecord: " << pExceptionPtrs->ContextRecord << endl;
cerr << "ExceptionRecord: " << pExceptionPtrs->ExceptionRecord << endl;

// Write minidump file
CreateMiniDump(pExceptionPtrs);

// Terminate process
TerminateProcess(GetCurrentProcess(), 1);

return EXCEPTION_EXECUTE_HANDLER;
}

int fib(unsigned int n) {
if(n == 0) return 0;
if(n == 1) return 1;
return fib(n-1)+fib(n-2);
}

int main(){
SetUnhandledExceptionFilter(SehHandler);
cout << fib(1000000);
return 0;
}

1

Решение

Да, вы можете получить мини-дамп из SO сбоев, но никогда так, как вы это делаете сейчас. Ваша функция SehHandler () выполняется в потоке, который вызвал исключение. И это в опасном состоянии, у вас осталось около 7080 байтов места для аварийного стека, чтобы сделать то, что вам нужно. Если вы потребляете это, то программа завершится с ошибкой с неуловимым нарушением прав доступа.

Вы не можете вызвать MiniDumpWriteDump () и надеяться выжить, эта функция требует больше стека, чем у вас есть. Так что это жесткий кабум без минидампа.

Тебе нужно другой поток, чтобы сделать этот вызов. Это может быть, например, поток, который вы создаете при инициализации и блокируете с помощью вызова WaitForMultipleObjects (). Ваш SehHandler () может вызвать SetEvent (), чтобы разбудить его. После записи значения PEXCEPTION_POINTERS в глобальную переменную. И блокировать на неопределенный срок, чтобы позволить потоку создать мини-дамп и прервать процесс.

Fwiw, безусловно, лучшее место для этой темы находится в другом процессе. Это также позволяет вам иметь дело с действительно неприятными, которые полностью портят состояние процесса. «Защитный» процесс, который вы запускаете при инициализации. С именованным событием, сигнализирующим об этом, и, скажем, отображенный в памяти файл для передачи PEXCEPTION_POINTERS. Не запускайте его в SehHandler (), куча процесса больше не надежна, поэтому CreateProcess () больше не может работать, вы должны сделать это рано.

9

Другие решения

Ответ Ханса Пассанта указывает, что существует 7080 байтов аварийного стека. Я не знаю, откуда эта информация, и он не ответил на @nop выше, и мои выводы показывают, что эта информация неверна. Однако этот сайт по какой-то причине не позволяет мне комментировать выше, поэтому я просто оставлю это здесь …

Есть функция, которая может использоваться для запроса и установки того, сколько аварийного стека осталось обработчику стека: SetThreadStackGuarantee(). Обратите внимание, что с Windows 10 определенно (но я думаю, что с Windows 7, а также), в большинстве случаев это значение будет 0. Так что по умолчанию в обработчике нет ничего сложного. Вы можете быть в состоянии сигнализировать о другом потоке или внешнем процессе, как предложил Ганс, но это все.

Однако, если вы не хотите реализовывать такое сложное решение и можете сэкономить свободное место в стеке, его проще всего использовать. SetThreadStackGuarantee() в установите для этого значения достаточно высокое, чтобы вы могли продолжить обработку исключения переполнения стека, как и любое другое. Обратите внимание, что вам нужно вызывать эту функцию в каждом потоке, который нуждается в этой функции, и вызывать ее до переполнение стека происходит, поэтому желательно при инициализации потока.

1

По вопросам рекламы [email protected]