(Translated by https://www.hiragana.jp/)
Введение в обработку структурированных исключений SEH
The Wayback Machine - https://web.archive.org/web/20140327055120/http://devdoc.web-ide.ru/index.php/content/view/seh_intro.htm
DevDoc home page DevDoc background gradient
 
   
Имя Пароль Запомнить Зарегистрироваться

Автор: Кудинов Александр
Последняя модификация: 2007-04-16 23:02:40

Введение в обработку структурированных исключений SEH

Введение

Исключения в C++ это механизм обработки ошибок. Все знают о стандартных исключениях C++, которые представлены ключевыми словами try/catch. В мире Windows существует еще один тип исключений: SE (Structured Exception) – структурированные исключения.

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

С точки зрения программы, обработка обоих видов исключений – одинаковая. В компиляторе MS VS есть ключевые слова __try/__except/__finally. Они позволяют полностью выполнять обработку структурированных исключений способом, похожим на обработку C++ исключений.

Эта статья открывает цикл, посвященный SEH. В первой статье мы рассмотрим средства среды Visual Studio для обработки структурированных исключений (SEH).

Использование структурированной обработки исключений

SEH это часть Windows. Разработчики ОС сделали удобную среду для перехвата и обработки ошибок в программе. В статье про отладку и запись минидампов описан один из вариантов использования этого механизма.

Несмотря на то, что SEH это часть ОС, основная нагрузка ложиться на компилятор. Он создает вспомогательный код, создает дополнительные структуры, отвечает за создание фрейма стеков и т.п. По непонятным причинам Майкрософт не предоставляет подробной документации по исключениям и надо полагаться целиком на компилятор.

Надо не путать SEH и С++ исключения. Избегайте использовать их одновременно. С++ исключения на низком уровне используют SEH, поэтому могут возникать конфликты.

SEH предоставляет обработчики двух типов:

  • Обработка завершения
  • Обработка исключений

Обработчик завершения

Обработчик завершения гарантирует, что некий код будет выполнен независимо от того, как завершиться другой блок:

__try 
{ 
} 
_finally // обработчик завершения 
{ 
}

Это очень похоже на синтаксис C++ исключений. С помощью ключевого слова __try мы защищаем участок кода. Теперь мы можем обрабатывать все события, которые в нем происходят.

В приведенном примере гарантируется, что блок __finaly будет выполнен независимо от того, как будет осуществлен выход из блока __try: по ошибке или с помощью операторов перехода return, goto. Даже если программист использует longjump – блок __finaly будет все равно выполнен.

Блок __finaly можно использовать для освобождения ресурсов, чтобы избежать из утечки.

Как видите – преимущества налицо. Надо только иметь ввиду, что локальная раскрутка требует значительного времени. Поэтому необоснованное использование этой конструкции может привести к существенному падению производительности. Наибольшие потери происходят если блок __try завершается преждевременно. В других случаях затраты времени минимальны.

Для уменьшения накладных расходов от преждевременного завершения существует ключевое слово _leave. Его можно использовать внутри блока __try. Когда компилятор встречает это слово – происходит выход из блока __try и выполнение блока __finaly. Т.е. его можно рассматривать как переход на закрывающуюся скобку блока __try.

Фильтры и обработчик исключений

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

При возникновении исключения, ОС дает программе шанс определить его тип и самостоятельно обработать. Для этого используются блоки __try/__except.

Обратите внимание, что __except не может использоваться совместно с __finaly, однако можно вложить блок __try/__finaly в блок __try/__except.

Синтаксис использования следующий:

__try 
{ 
} 
__except (фильтр) 
{ 
// обработчик исключений 
}

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

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

  • EXCEPTION_EXECUTE_HANDLER
  • EXCEPTION_CONTINUE_SEARCH
  • EXCEPTION_CONTINUE_EXECUTION

EXCEPTION_EXECUTE_HANDLER

Обозначает, что блок __except содержит код для обработки исключения. Т.е. программа готова к его обработке. Когда возникает исключение - происходит глобальная раскрутка, потом управление предается коду обработчика. После его завершения система считает ошибку обработанной и продолжает выполнение.

Возобновление работы происходит на строке следующей за блоком __except.

В этом смысле обработка похожа на стандартные исключения C++: try/catch.

Глобальная раскрутка начинается с самого вложенного блока __try. При этом будут выполняться все блоки __finaly/__except, которые ему соответствуют. Потом обрабатывается вышележащий блок и так до тех пор, пока не будет достигнут блок, который сможет обработать исключение.

Обратите внимание. Если во вложенном блоке __finaly выполниться оператор return – это остановит глобальную раскрутку.

EXCEPTION_CONTINUE_EXECUTION

В этом случае блок __except не будет выполнятся. Система передаст управление обратно на инструкцию, которая вызвала исключение. На первый взгляд, мы получим бесконечный процесс: инструкция будет вызывать исключение снова и снова, а система будет передавать ей управление.

Для разрешения такой проблемы используют функции-фильтры. Эта функция пишется в качестве выражения в блоке __except.

__try{}
__except(filter())
{}
LONG filter()
{
  //код для исправления ошибки
  return EXCEPTION_CONTINUE_EXECUTION;
}

Т.е. функция filter пытается исправить ошибку и выдать инструкции системе, что делать с исключением дальше. В данном случае, система сделает перезапуск проблемной инструкции. Если же функция не смогла исправить ошибку, она может вернуть EXCEPTION_EXECUTE_HANDLER. Это приведет к выполнению обработчика в блоке __except.

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

Фильтр исключений может использовать функции GetExceptionCode/GetExceptionlnformation чтобы проанализировать причину ошибки. Об использовании этой функции я подробно расскажу в следующей статье.

EXCEPTION_CONTINUE_SEARCH

Это значение сообщает системе, что надо продолжить поиск обработчика исключения вверх по стеку. Если фильтр исключений возвращает эту константу – это равнозначно тому, что ошибка не обработана.

Заключение

В статье даны основы структурной обработки исключений (SEH). В отличие от C++ исключений – они являются частью системы и могут использоваться из любого языка программирования.

В следующих статьях этого цикла я разберу тонкости использования исключений на примерах.

Подпишитесь, чтобы получать все новые статьи с сайта первым!

Оценить статью Текущий рейтинг: 3.4783. Проголосовало 23 человек.

Коментарии к статье

не __finaly, а __finally

Добавить комментарий

Вы можете добавлять свои комментарии, пожелания или вопросы к статье. Они будут видны всем пользователям, а также автору статьи. Войдите в систему под своим именем, чтобы другие пользователи могли видеть, кто автор сообщения. Форма для входа расположена вверху страницы. Если у Вас нет аккаунта на сайте - рекомендуем зарегистрироваться. Это займет всего пару минут.

Отправлять сообщения могут только зарегистрированные пользователи

Copyright (C) Kudinov Alexander, 2006-2014

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

Generation time: 0.018288135528564 seconds