Механическое удерживание земляных масс: Механическое удерживание земляных масс на склоне обеспечивают контрфорсными сооружениями различных конструкций...
Папиллярные узоры пальцев рук - маркер спортивных способностей: дерматоглифические признаки формируются на 3-5 месяце беременности, не изменяются в течение жизни...
Топ:
Установка замедленного коксования: Чем выше температура и ниже давление, тем место разрыва углеродной цепи всё больше смещается к её концу и значительно возрастает...
Когда производится ограждение поезда, остановившегося на перегоне: Во всех случаях немедленно должно быть ограждено место препятствия для движения поездов на смежном пути двухпутного...
Интересное:
Подходы к решению темы фильма: Существует три основных типа исторического фильма, имеющих между собой много общего...
Уполаживание и террасирование склонов: Если глубина оврага более 5 м необходимо устройство берм. Варианты использования оврагов для градостроительных целей...
Берегоукрепление оползневых склонов: На прибрежных склонах основной причиной развития оползневых процессов является подмыв водами рек естественных склонов...
Дисциплины:
2020-04-01 | 128 |
5.00
из
|
Заказать работу |
|
|
Давайте немного отдохнем и суммируем все сказанное выше. SEH – это системный сервис, в котором унифицирован механизм обработки исключений, все обработчики текущего потока регистрируются в списке регистрации обработчиков исключений. Если в функции встречается конструкция __try … __except, то создается код, который регистрирует новый обработчик исключения и помещает информацию о нем в стек. Во время завершения функции (а точнее, после того, как управление вышло из секции __try), функция разрегистрирует обработчик. Значит, если к текущему моменту в стеке находится три функции, каждая из которых установила свой обработчик исключения, то в списке обработчиков исключения должно находиться по крайней мере три обработчика, а в стеке должны находиться три записи об обработчиках исключений. Информация о текущем обработчике доступна по адресу fs:[0]. Runtime-библиотека регистрирует свой обработчик исключений, который (если исключение не обрабатывается приложением) вызывает функцию UnhandledExceptionFilter, после чего приложение завершается с выводом диалогового окна «Application Error».
Теперь настало время написать код, который бы использовал сказанное выше и подтвердил правильность наших суждений. Давайте напишем простую функцию, которая бы пробегала по всем зарегистрированным обработчикам и выводила информацию о них на экран. Код функции приведен ниже:
void zWalkThroughSEH() { _EXCEPTION_REGISTRATION * pVCExcRec; __asm mov eax, FS:[0] __asm mov [pVCExcRec], EAX // Перебираем блоки в связанном списке. 0xFFFFFFFF означает конец списка. printf("Exception Registration chain:\n"); while (0xFFFFFFFF!= (unsigned)(UINT_PTR)pVCExcRec) { printf("\tCurrent SEH record: 0x%X\n\tPrev SEH Record: 0x%X\n\tHandler: 0x%X\n\n", pVCExcRec, pVCExcRec->prev, pVCExcRec->hander); pVCExcRec = (_EXCEPTION_REGISTRATION *)(pVCExcRec->prev); } } |
Вызов эту функции после начала выполнения функции main покажет, что к моменту выполнения функции main в списке обработчиков уже зарегистрированы два обработчика. Текущий обработчик, как было показано раньше, установлен библиотекой Runtime. А вот последний установлен системой.
|
Exception Registration chain: Current SEH record: 0x12FFB0 Prev SEH Record: 0x12FFE0 Handler: 0x41123A Current SEH record: 0x12FFE0 Prev SEH Record: 0xFFFFFFFF Handler: 0x77E94809 |
Как вы, наверное, уже догадались, создавать свой обработчик и располагать его за системным нет никакого смысла, поскольку исключение будет обработано в runtime-библиотеке, и приложение будет завершено. Тогда я попытался создать свой обработчик и расположил информацию о нем перед обработчиком runtime-библиотеки, выделив для него место в динамической памяти, но увы, мое приложение просто было выгружено из памяти после возникновения исключения, а вставленный обработчик не был выполнен. Как оказалось, так делать нельзя потому, что все записи списка обработчиков исключений должны лежать в стеке, причем каждая следующая запись должна быть расположена выше предыдущей.
Итак, нельзя расположить информацию об обработчике перед информацией о runtime-обработчике. Но никто не мешает переписать значение поля hander обработчика runtime-библиотеки, установив его так, чтобы он указывал на нашу функцию. Код, который реализует это, приведен ниже.
void zHookUpSEHChain(SEHHandler handler) { _EXCEPTION_REGISTRATION * pVCExcRec; __asm mov eax, FS:[0] __asm mov [pVCExcRec], EAX // Перебираем блоки в связанном списке. 0xFFFFFFFF означает конец списка. while (0xFFFFFFFF!= (unsigned)(UINT_PTR)pVCExcRec) { if ((unsigned)(UINT_PTR)pVCExcRec->prev->prev == 0xFFFFFFFF) { defHandler = pVCExcRec->hander; pVCExcRec->hander = handler; break; } pVCExcRec = (_EXCEPTION_REGISTRATION *)(pVCExcRec->prev); } } |
где
defHandler – статическая переменная, в которой сохраняется адрес предыдущего обработчика.
handler – наш обработчик исключения.
Разумеется, внимательный читатель уже заметил некоторую нелогичность в этих суждениях. Зачем пытаться зарегистрировать свой обработчик таким изощренным методом, если достаточно поместить свой блок __try __except в функции main? Дело в том, что при использовании MFC, ATL или какой-то иной библиотеки не имеется доступа к пользовательской точке входа, и, стало быть, нельзя установить свой обработчик.
|
Сейчас пришло время собрать воедино все сказанное выше и написать небольшую программу, иллюстрирующую способ установки обработчика. К статье прилагается файл ehSimple.cpp, в котором вы найдете код установки обработчика. Первый обработчик реализован в виде класса CatUnhandledExceptionFilter, объявленного следующим образом:
class CatUnhandledExceptionFilter { private: // SEHHandler oldHandler – переменная, в которую будет записан адрес //предыдущего обработчика исключения. Объявление типа SEHHandler // было приведено выше. static SEHHandler oldHandler; static void zHookUpSEHChain(SEHHandler handler); static int myHandler(PEXCEPTION_RECORD pEhRecors, PEXCEPTION_REGISTRATION pEhRegRecord, PCONTEXT pContext, void* pp); public: CatUnhandledExceptionFilter(); ~CatUnhandledExceptionFilter(); }; |
static void zHookUpSEHChain(SEHHandler handler); – это функция для подмены обработчика исключений runtime-библиотеки. Код ее почти не отличается от предложенного ранее. Единственным изменением является переменная, в которой сохраняется адрес предыдущего обработчика.
static int myHandler(PEXCEPTION_RECORD pEhRecors, PEXCEPTION_REGISTRATION pEhRegRecord, PCONTEXT pContext, PEXCEPTION_RECORD pp); - это наш обработчик, который будет вызван в случае возникновения необработанного исключения.
int CatUnhandledExceptionFilter::myHandler(PEXCEPTION_RECORD pEhRecors, PEXCEPTION_REGISTRATION pEhRegRecord, PCONTEXT pContext, void* pp) { printf("*** In My Handler ***\n"); printf("Exception address: 0x%X\n", pEhRecors->ExceptionAddress); printf("Exception code: 0x%X\n", pEhRecors->ExceptionCode); return CatUnhandledExceptionFilter::oldHandler(pEhRecors, pEhRegRecord, pContext, pp); } |
В программе создается статический объект типа CatUnhandledExceptionFilter. Во время создания этого объекта в конструкторе вызывается функция подмены самого верхнего обработчика исключений. После того, как статические объекты приложения созданы, runtime передает управление функции main, в которой генерируется исключение по доступу к памяти, в результате чего управление переходит нашему обработчику исключения, который сейчас не делает ничего, а просто выводит информацию об исключении на экран и передает управление подмененному обработчику.
После возникновения необработанного исключения операционная система вызывает наш обработчик для обработки исключения и он, выполнив то, что ему нужно, передет управление дальше.
|
Недостатком приведенного выше кода является то, что он работоспособен только в однопоточных приложениях. Все это происходит потому, что указатель на вершину цепочки EXCEPTION_REGISTRATION находится в структуре TIB, которая хранит в себе информацию о текущем потоке, а значит, при вставке обработчика исключения с использованием значение FS:[0] мы установим обработчик только для одного потока.
Но что же делать в случае многопоточного приложения? Для этого, видимо, нужно проделать описанные действия для каждого потока. К счастью, этого делать не придется. В следующем разделе вы увидите, как обработать необработанные исключения во всех потоках.
|
|
Типы оградительных сооружений в морском порту: По расположению оградительных сооружений в плане различают волноломы, обе оконечности...
Индивидуальные очистные сооружения: К классу индивидуальных очистных сооружений относят сооружения, пропускная способность которых...
Поперечные профили набережных и береговой полосы: На городских территориях берегоукрепление проектируют с учетом технических и экономических требований, но особое значение придают эстетическим...
Организация стока поверхностных вод: Наибольшее количество влаги на земном шаре испаряется с поверхности морей и океанов (88‰)...
© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!