Интернет магазин китайских планшетных компьютеров



Компьютеры - Структурная обработка исключений

23 января 2011





Структурная обработка исключений — механизм обработки программных и аппаратных исключений в ОС Microsoft Windows, позволяющий программистам контролировать обработку исключений, а также являющийся отладочным средством.

Исключения и обработка исключений

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

Реализация

Ключевые слова

Механизм поддерживается Microsoft только на уровне компилятора с помощью реализации нестандартных синтаксических конструкций _try, _except и _finally. Ключевое слово _try используется для выделения участка кода, в котором генерация исключения будет обработана одним или несколькими блоками _except. Код, находящийся в блоке _finally, выполнится всегда и независимо от других блоков _try и _except.

Пример использования в языке C/C++

_try {
        // защищенный код,
        // который помещается в SEH-фрейм
}
_except  {
        // обработчик исключений
}
_finally {
        // выполняющийся в любом случае код
}

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

  • EXCEPTION_EXECUTE_HANDLER — указывает на возможность данного обработчика обработать исключение. При получении такого значения операционная система прекращает поиск релевантных обработчиков исключения и, выполнив раскрутку стека, передаёт управление первому, вернувшему значение EXCEPTION_EXECUTE_HANDLER
  • EXCEPTION_CONTINUE_EXECUTION — указывает на исправление ошибки. Система снова передаст управление на инструкцию, которая вызвала исключение, поскольку предполагается, что в этот раз она не вызовет исключение.
  • EXCEPTION_CONTINUE_SEARCH — указывает, что подходящий обработчик может быть найден вверх по стеку. В то же время возвращение этого значения может быть свидетельством того, что ошибка не обработана.

Используемые структуры и механизмы

Каждый поток любого процесса использует регистр fs для хранения указателя на структуру данных Thread Information Block, которая хранит информацию об этом потоке. В этой структуре хранится указатель на последнюю из связанного списка зарегистрированную структуру _EXCEPTION_REGISTRATION_RECORD, включающую указатель на обработчик исключения и указатель на предыдущую запись _EXCEPTION_REGISTRATION_RECORD. При создании потока операционная система добавляет обработчик исключения по умолчанию, вызываемый функцией 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 для проведения очистки. Если ни один из установленных программистом фильтров обработчиков исключений не вернул EXCEPTION_EXECUTE_HANDLER или EXCEPTION_CONTINUE_EXECUTION, то происходит выполнение UnhandledExceptionFilter — фильтра обработчика исключений по умолчанию, который регистрируется при подготовке потока к запуску.

Вызов обработчика

При возникновении исключения операционная система не вызывает напрямую фильтр исключений, а передаёт его адрес функции ___except_handler3, откуда и вызывается функция-фильтр. Она использует следующую структуру данных:

struct _EXCEPTION_REGISTRATION{
     struct _EXCEPTION_REGISTRATION *prev;
     void (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. Функция ___except_handler3 вызывает нужный фильтр и до вызова обработчика производит раскрутку стека функцией ntdll.dll!RtlUnwind.

Если ни один из установленных программистом обработчиков не согласился обработать исключение, то вызывается функция UnhandledExceptionFilter, которая проверяет, запущен ли процесс под отладчиком, и информирует его, если он доступен. После этого функция вызывает фильтр умалчиваемого обработчика. Затем, в зависимости от настроек операционной системы, вызывается либо отладчик, либо функция NtRaiseHardError, которая отображает сообщение об ошибке.



Просмотров: 1185


<<< Windows Presentation Foundation