Механизмы обработки исключительных ситуаций

Автор работы: Пользователь скрыл имя, 21 Мая 2013 в 00:23, курс лекций

Описание работы

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

Файлы: 1 файл

08. Механизмы обработки исключительных ситуаций.docx

— 67.11 Кб (Скачать файл)

Несмотря на то, что SEH является составной частью ОС, основная нагрузка ложится на компилятор: он создает вспомогательный код и отвечает за создание фрейма стеков. Этот механизм реализован в компиляторе Visual C++ MS Visual Studio с помощью конструкций:

 

 __try {

  <контролируемый программный код>

} __except {

       <программный код обработки исключения>

  }

 

и

 

__try {

  <контролируемый программный код>

} __finally {

      <программный код завершения обработки исключений>

       }

 

Инструкция __except не может использоваться совместно с инструкцией __finally, однако можно вложить конструкцию __try …__finally в конструкцию __try …__except.

 

SEH предоставляет два варианта обработки исключений:

  • обработку исключений;
  • завершение обработки исключений.

 

8.2.2.1   Обработка исключений SEH

 

При возникновении исключения ОС предоставляет возможность программе определить тип исключения и обработать его с помощью инструкции __except:

 

__try {

  <контролируемый программный код>

} __except (<функция-фильтр>)

      <программный код обработки исключения>

     }

 

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

 

EXCEPTION_EXECUTE_HANDLER

 

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

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

 

EXCEPTION_CONTINUE_SEARCH

 

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

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

__try{

  <контролируемый программный код>

} __except (filter ( )) {

      <программный код обработки исключения>

  }

 

LONG filter ( )

{ // код исправления ошибки

  …

  return EXCEPTION_CONTINUE_EXECUTION;

}

 

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

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

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

 

EXCEPTION_CONTINUE_EXECUTION

 

В этом случае ОС продолжит поиск обработчика исключения вверх по стеку блоков __try. Т.о., если фильтр исключений возвращает эту константу, то это равнозначно тому, что ошибка не обработана.

 

8.2.2.2   Завершение обработки исключений SEH

 

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

__try {

  <контролируемый программный код>

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

      <программный код завершения>

     }

 

При этом гарантируется, что блок __finally будет выполнен независимо от того, как будет осуществлен выход из блока __try: по ошибке или с помощью операторов перехода (return или goto)6.

Обычно инструкция __finaly используется для освобождения ресурсов, динамически захваченных программой (чтобы избежать из «утечки»).

Следует учесть, что использование механизма SEH требует значительного времени, - поэтому необоснованное его использование может привести к существенному производительности программы. Наибольшие потери при этом происходят, если выполнение контролируемого программного кода завершается преждевременно. Для уменьшения этих накладных расходов в контролируемом программном коде следует использовать инструкцию _leave. Когда компилятор встречает это ключевое слово, то происходит выход из контролируемого программного кода и выполнение инструкции __finally.

8.2.2   Глобальная обработка исключений в С++

 

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

Для перехвата глобальных исключений существуют две функции, описанные в заголовочном файле <stdlib.h>: _set_purecall_handler и SetUnhandledExceptionFilter.

 

Функция:

 

_purecall_handler _set_purecall_handler (_purecall_handler function)

 

устанавливает callback-функцию function типа _purecall_handler для обработки событий, связанных с вызовом чисто виртуальных функций. Эта функция должна иметь тип возвращаемого значения void. Такой обработчик исключений является глобальным для всех используемых в приложении библиотек динамической компоновки DLL7 и вызываемых EXE-программ. Так, например, программа:

 

// compile with: /W1

#include <tchar.h>

#include <stdio.h>

#include <stdlib.h>

 

class CDerived;

class CBase {

public:

   CBase (CDerived *derived): m_pDerived (derived) { };

   ~CBase ( );

   virtual void function (void) = 0;

   CDerived * m_pDerived;

};

 

class CDerived : public CBase

{

  public:

   CDerived ( ) : CBase (this) { };  

   virtual void function (void) { };

};

 

CBase::~CBase ( )

{

   m_pDerived -> function ( );

}

 

void myPurecallHandler (void)

{

   printf ("In _purecall_handler.");

   exit (0);

}

 

int _tmain(int argc, _TCHAR* argv [ ])

{

   _set_purecall_handler (myPurecallHandler);

   CDerived myDerived;

}

 

выведет сообщение: In _purecall_handler

 

Функция:

 

LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter (

  __in  LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter

);

 

устанавливает обработчик SEH8 для структурных исключений. Этот обработчик перехватит все исключения, которые произошли в любых потоках и не обработаны программой при помощи try … catch. Например:

 

LONG __stdcall MainExceptionHandler (EXCEPTION_POINTERS* exceptionInfo) 
{ // обработка данных с использованием exceptionInfo  
  return EXCEPTION_CONTINUE_SEARCH; 

void MainOnPureCallHandler (void) 

   MessageBoxA (NULL, "Application just crashed!\n\nError: Pure virtual call!",    

                      "Application error.", MB_OK | MB_ICONERROR); 
    _exit (0); 

 
// это нужно выполнить сразу после старта приложения 
// устанавливаем callback-функции для обработки исключительных ситуаций 
_set_purecall_handler (MainOnPureCallHandler); 
SetUnhandledExceptionFilter (MainExceptionHandler); 
 
// это нужно выполнить перед завершением приложения 
SetUnhandledExceptionFilter (NULL); 
_set_purecall_handler (NULL);

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

 

1 под робастностью программы понимается её свойство сохранять работоспособность при возникновении различного рода исключительных ситуаций

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

3 декларация исключения представляет собой ссылку на объект-исключение

4 SEH - Structured Exception Handling

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

6 даже если программа выполнит инструкцию longjump, то программный код завершения будет все равно выполнен

7 DLL – Dynamic Link Library

8 SEH - Structured Exception Handling

 


Информация о работе Механизмы обработки исключительных ситуаций