Структурированная обработка исключений


Структурированная обработка исключений (англ. SEH — Structured Exception Handling) — механизм обработки программных и аппаратных исключений в операционной системе Microsoft Windows, позволяющий программистам контролировать обработку исключений, а также являющийся отладочным средством[1].

Исключение — это событие при выполнении программы, которое приводит к её ненормальному или неправильному поведению. Существует два вида исключений: аппаратные, которые генерируются процессором, и программные, генерируемые операционной системой и прикладными программами. Механизм структурной обработки исключений позволяет однотипно обрабатывать как программные, так и аппаратные исключения.

Механизм поддерживается Microsoft только на уровне компилятора с помощью реализации нестандартных синтаксических конструкций __try, __except и __finally. Ключевое слово __try используется для выделения участка кода, в котором генерация исключения будет обработана одним или несколькими блоками __except. Код, находящийся в блоке __finally, выполнится всегда и независимо от других блоков __try и __except[2].

В качестве фильтра исключений могут выступать обычные функции, возвращающие три константных выражения:[3]

Каждый поток любого процесса использует регистр (16-разрядный селектор) fs для хранения указателя на структуру данных Thread Information Block, содержащей информацию об этом потоке. В этой структуре хранится указатель на последнюю из связанного списка зарегистрированную структуру _EXCEPTION_REGISTRATION_RECORD, включающую указатель на обработчик исключения и указатель на предыдущую запись _EXCEPTION_REGISTRATION_RECORD.[5] При создании потока операционная система добавляет обработчик исключения по умолчанию, вызываемый функцией kernel32!UnhandledExceptionFilter.

Каждый раз, когда программист использует конструкцию __try, происходит добавление нового экземпляра структуры _EXCEPTION_REGISTRATION_RECORD, указывающей на функцию _except_handler3 библиотеки msvcrt.dll, в стек потока. Код, заключающийся в блоках __except и __finally вызывается из _except_handler3. В конце блока __try компилятор добавляет код, который удаляет текущую запись _EXCEPTION_REGISTRATION_RECORD и восстанавливает значение указателя fs:0 на предыдущую запись.