- Структурная обработка исключений
-
Структурная обработка исключений (англ. SEH — Structured Exception Handling) — механизм обработки программных и аппаратных исключений в ОС Microsoft Windows, позволяющий программистам контролировать обработку исключений, а также являющийся отладочным средством[1].
Содержание
Исключения и обработка исключений
См. также: Обработка исключенийИсключение — это событие при выполнении программы, которое приводит к её ненормальному или неправильному поведению. Существует два вида исключений: аппаратные, которые генерируются процессором, и программные, генерируемые операционной системой и прикладными программами. Механизм структурной обработки исключений позволяет однотипно обрабатывать как программные, так и аппаратные исключения.
Реализация
Ключевые слова
Механизм поддерживается Microsoft только на уровне компилятора с помощью реализации нестандартных синтаксических конструкций
_try
,_except
и_finally
. Ключевое слово_try
используется для выделения участка кода, в котором генерация исключения будет обработана одним или несколькими блоками_except
. Код, находящийся в блоке_finally
, выполнится всегда и независимо от других блоков_try
и_except
[2].Пример использования в языке C/C++
_try { // защищенный код, // который помещается в SEH-фрейм } _except (фильтр исключений) { // обработчик исключений } _finally { // выполняющийся в любом случае код }
В качестве фильтра исключений могут выступать обычные функции, возвращающие три константных выражения:[3]
EXCEPTION_EXECUTE_HANDLER
— указывает на возможность данного обработчика обработать исключение. При получении такого значения операционная система прекращает поиск релевантных обработчиков исключения и, выполнив раскрутку стека, передаёт управление первому, вернувшему значение EXCEPTION_EXECUTE_HANDLER
EXCEPTION_CONTINUE_EXECUTION
— указывает на исправление ошибки. Система снова передаст управление на инструкцию, которая вызвала исключение, поскольку предполагается, что в этот раз она не вызовет исключение.[4]
EXCEPTION_CONTINUE_SEARCH
— указывает, что подходящий обработчик может быть найден выше по стеку. В то же время возвращение этого значения может быть свидетельством того, что ошибка не обработана.[3]
Используемые структуры и механизмы
Каждый поток любого процесса использует регистр (16ти разрядный селектор)
fs
для хранения указателя на структуру данных Thread Information Block, содержащей информацию об этом потоке. В этой структуре хранится указатель на последнюю из связанного списка зарегистрированную структуру _EXCEPTION_REGISTRATION_RECORD, включающую указатель на обработчик исключения и указатель на предыдущую запись _EXCEPTION_REGISTRATION_RECORD.[5] При создании потока операционная система добавляет обработчик исключения по умолчанию, вызываемый функциейkernel32!UnhandledExceptionFilter
.Прототип callback функции-обработчика следующий:
EXCEPTION_DISPOSITION __cdecl _except_handler( struct _EXCEPTION_RECORD *ExceptionRecord, void * EstablisherFrame, struct _CONTEXT *ContextRecord, void * DispatcherContext );
Каждый раз, когда программист использует конструкцию
_try
происходит добавление нового экземпляра структуры _EXCEPTION_REGISTRATION_RECORD, указывающей на функцию ___except_handler3 библиотеки msvcrt.dll, в стек потока. Код, заключающийся в блоках_except
и_finally
вызывается из ___except_handler3. В конце блока_try
компилятор добавляет код, который удаляет текущую запись _EXCEPTION_REGISTRATION_RECORD и восстанавливает значение указателяfs:0
на предыдущую запись.Когда происходит исключение, система последовательно перебирает всю цепочку обработчиков прерываний. Каждый обработчик возвращает значение указывающее на то, может ли он обработать это исключение или нет. Указателем конца списка доступных обработчиков исключения является значение
FFFFFFFF
, располагаемое в стеке за последним обработчиком. Если система находит нужный обработчик, то управление передаётся ему. При этом, после нахождения релевантного обработчика возникшего исключения, операционная система не сразу передаёт ему управление, а ещё раз последовательно вызывает все обработчики по цепочке с флагомEH_UNWINDING
для проведения очистки (вызова деструктора ).[6] Если ни один из установленных программистом фильтров обработчиков исключений не вернул EXCEPTION_EXECUTE_HANDLER или EXCEPTION_CONTINUE_EXECUTION, то происходит выполнениеUnhandledExceptionFilter
— фильтра обработчика исключений по умолчанию, который регистрируется при подготовке потока к запуску.Вызов обработчика
При возникновении исключения операционная система не вызывает напрямую фильтр исключений (который отвечает за то, будет ли конкретный обработчик обрабатывать возникшее исключение или нет), а передаёт его адрес функции
___except_handler3
, откуда и вызывается функция-фильтр. Она использует следующую структуру данных:[7]struct _EXCEPTION_REGISTRATION{ struct _EXCEPTION_REGISTRATION *prev; void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_REGISTRATION, PCONTEXT, PEXCEPTION_RECORD); struct scopetable_entry *scopetable; int trylevel; int _ebp; PEXCEPTION_POINTERS xpointers; };
Поле
*scopetable
указывает на адрес массива структурscopetable_entry
, а целочисленное поле trylevel — индекс в этом массиве. Поле_ebp
содержит значение указателя кадра стека, существовавшего до создания структуры EXCEPTION_REGISTRATION.[8] Функция___except_handler3
вызывает нужный фильтр и до вызова обработчика производит раскрутку (очистку) стека функциейntdll.dll!RtlUnwind
.Если ни один из установленных программистом обработчиков не согласился обработать исключение, то вызывается функция
UnhandledExceptionFilter
, которая проверяет, запущен ли процесс под отладчиком, и информирует его, если он доступен.[8] После этого функция вызывает фильтр умалчиваемого обработчика (который устанавливается функциейSetUnhandledExceptionFilter
и который всегда возвращает EXCEPTION_EXECUTE_HANDLER).[8] Затем, в зависимости от настроек операционной системы, вызывается либо отладчик, либо функция NtRaiseHardError, которая отображает сообщение об ошибке.[8]См. также
Примечания
- ↑ Structured Exception Handling (Windows).
- ↑ About structured Exception Handling (Windows).
- ↑ 1 2 Введение в обработку структурированных исключений SEH.
- ↑ Win32 SEH изнутри.
- ↑ Эксплуатирование SEH в среде Win32.
- ↑ WASM.RU Win32 SEH изнутри (ч.1).
- ↑ WASM.RU Win32 SEH изнутри (ч.2).
- ↑ 1 2 3 4 WASM.RU Win32 SEH изнутри (ч.3).
Категории:- Концепции языков программирования
- Управление потоком
- Программные интерфейсы Microsoft
Wikimedia Foundation. 2010.