Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Системное программирование и WinAPI > SEH |
Автор: FCM 17.8.2009, 18:17 |
Почему-то с помощью SEH не удается отследить EXCEPTION_INT_OVERFLOW. Не подавляется (обрабатывается) ли оно аппаратно? |
Автор: GoldFinch 17.8.2009, 19:24 |
FCM, такое аппаратное исключение вообще бывает? что-то сомневаюсь %) |
Автор: FCM 17.8.2009, 19:40 |
Формально приведено в одной книжке (Рихтер "Windows via С/С++") в главе про SEH |
Автор: GoldFinch 17.8.2009, 21:27 |
вообщето оно генерится инструкцией into как вы его генерили? |
Автор: GremlinProg 18.8.2009, 08:13 | ||||
FCM, представляешь, сколько бы проблем было при поднятии такого исключения на автомате? флаг OF(overflow) очень часто используется штатно для определения критериев завершения циклов, поэтому такое переполнение не генерируется по-умолчанию если нужно, просто генерируй его сам:
into - тоже подойдет, но оно тестирует OF, конкретно по факту операции, типа такого:
|
Автор: GremlinProg 18.8.2009, 10:19 | ||
при чем тут сброс? add, inc, sub, dec, mul - все устанавливают OF в соответствии с результатом, сброс тут не нужен, если нужно что-то более сложное - встроенный ассемблер в помощь, а без него - RaiseException, как я уже показал |
Автор: GoldFinch 18.8.2009, 12:17 |
GremlinProg, RaiseException который ты показал сводит на нет весь смысл into, изза немеряного оверхеда, непонятно вообще зачем бросать EXCEPTION_INT_OVERFLOW если можно бросить чтоугодно, всеравно там if как устанавливается и сбрасывается OF я знаю, любая арифметическая инструкция, в том числе cmp, между сложением и into поменяет OF, кроме того, порядок вызова операторов перед __asm никем не гарантируется, a+=b; x+=y; __asm into может скомпилироваться в аналог x+=y; a+=b; __asm into |
Автор: GremlinProg 18.8.2009, 12:44 | ||||
into тут ни при чем, смысл RaiseException как раз в поднятии исключения без использования асма, и соответственно into RaiseException - равнозначная замена, только с учетом того, что тут можно бросить не обязательно EXCEPTION_INT_OVERFLOW, а любое другое, которое программа в состоянии обработать (вплоть до критического) любой программист в состоянии завести свой список исключений и работать с ним в дополнение ко всем системным исключениям (mc.exe в помощь) if тут опять же ни при чем, т.к. от OF и into тут уже ни чего не будет зависеть
не любая чтобы порядок не имел значения, у программиста должен быть другой оч. полезный инструмент - голова GoldFinch, если тебе есть что сказать в тему - я не против, всегда рад разделить мнение, но если будешь по-прежнему опоражнять пустой стакан, я тебе в него налью воды, не сомневайся |
Автор: GoldFinch 18.8.2009, 13:00 | ||
GremlinProg, дополнительное вычисление(?) "result >> 32" + if это в сотни раз медленнее однобайтовой into которая выполняется за 0 или 1 тактов, это называется "оверхед" без into это должно реализовываться как jo/jno - тот же if, и это замена одного подхода на другой, можно писать into, можно писать jo, это разная логика кода - исключение и условие какая?
это вообще к чему? |
Автор: GremlinProg 18.8.2009, 13:41 | ||||||
это к теме не относится, причем даже "сотни раз" - это уже перебор
поздравляю, GoldFinch, ты освоил начальные навыки ассемблера, только к теме это так же не относится
это было наглядно продемонстрировано моим первым постом очевидно все те арифметические операции, которые это переполнение не генерируют: DIV, IDIV, и т.п. это к тому, что если не предусмотрено вычисление выражения, в ходе которого происходит переполнение, то разницы нет, какая команда это переполнение сгенерировало, результат в любом случае будет неверным |
Автор: GoldFinch1 18.8.2009, 14:08 | ||
Признаю я был не прав. Как часто бывает, уверенность в своих знаниях меня подвела. Решив посмотреть как ведет себя div, я скомпилил в фасме код
запустил, и получил пресловутый Integer Overflow. Все таки не into единым. Уважаемый GremlinProg, опомнись, и перестать писать то чего не знаешь. Ты вводишь в заблуждение участников форума, да и выглядит это не красиво. Любой справочник говорит: DIV -- Unsigned Divide Flags Affected OF, SF, ZF, AR, PF, CF are undefined. За сим отправляюсь отдыхать недельку, пока основной акк в бане. |
Автор: GremlinProg 18.8.2009, 14:26 | ||||
я даже сохраню это на память ) уважаемый GoldFinch, честно говоря не знаю где ты мог получить в этом коде Integer Overflow, очевидно где-то ранее предоставленного кода, но опираясь даже на справку, которую ты так любезно нам предоставил: are undefined означает не определено, т.е. не затрагиваются, они могут затрагиваться любыми предыдущими операциями, но не данной совсем не обязательно было лезть в бутылку, только ради того, чтобы посмешить народ, хотя, признаю, тема стала интересна только благодаря тебе, спасибо! |
Автор: FCM 18.8.2009, 16:59 |
Да никак не генерил - прочитал книгу, попробовал . И почему это называется аппаратным исключением, если я его сам должен генерить? Было бы разумным иметь опцию в свойствах проекта, включающую/отключающую генерацию этого исключения. Кстати пробовал еще с помощью EXCEPTION_ARRAY_BOUNDS_EXCEEDED отловить выход за пределы С-массива - то же безрезультатно (в Debug это ловилось RTL'ю, а в Release- никак) A EXCEPTION_FLT_*** фиксируется (после того как контрольным словом отключить их FPU-обработу). Хотя тут два момента непонятны. 1) Если аппаратное FLT-исключение нигде не обработано, Windows его определяет (выдает правильный 16-чный код исключения), но почему-то называет unknown software exception 2) Просматривал статусное слово различных FLT-операций и заметил, что в Release фиксируется меньше критических FLT-событий. Если Debug и Release отличается толко настройками RTL, то как настройки RTL влияют на FPU-обработку FLT-исключений.? Если взять простое консольное приложение, то "казалось бы" после его одевания при компоновке в SEH-фреймы оно должно иметь внешний фрейм от windows, потом фреймы (или аналоги?) от RTL, потом пользовательские (если есть) ловушки, а аппаратные средства обработки еще глубже. И каким боком туда залезает RTL (в С++ еще минимально , в некоторых языках еще более выраженно). Не совсем понятно, что собственно генерит аппаратные исключения - CPU/FPU или какие-нибудь драйвера. Также не понятно, как FPU обрабатывает EXCEPTION_FLT_*** действительно аппаратно или драйвера. Функции VС++ напрямую работают c железом или через WinApi ? Например попытка открыть несуществующий файл - приводит к соответствующему errno. Кто его назначает? Это же программное исключение? |
Автор: GremlinProg 19.8.2009, 10:55 | ||||||||||||||
ну, потому что процессор не знает ни EXCEPTION_INT_OVERFLOW, ни любой другой статус, привычный нам, он просто генерирует аппаратное прерывание, которое перемещает исполнение кода на соответствующий адрес в векторе прерываний, а оттуда уже операционка нас информирует о случившемся через SEH (в документации такие прерывания обозначаются через решетку: #OF(overflow), #DE(divide error) и т.п.)
в принципе, может и появится в будущем, есть же опция /fp:except, которая расставляет WAIT'ы после любых обращений к FPU тут в принципе аналогично - после целочисленных вычислений вставлять into, но по-моему, от этого будет только больше проблем, чем пользы
ну так проверка на выход за границы массива только в дебаге и ведется, можешь и в релизе ее включить, только зачем оно надо, это ведь отладочный механизм
сопроцессор и генерит
он не обрабатывает EXCEPTION_FLT_*** он обрабатывает свои контрольные регистры: если поднят флаг исключения (одного из 6), и если это исключение выключено по маске, то генерирует какое-то общее прерывание для исключений (смотри документацию, не помню какое именно) если исключение маскируется, то FPU просто заменяет результат одним из табличных значений:
и продолжает работать дальше
с железом работают драйвера, а errno ставит CRT, и это уже не исключение, это что-то вроде упрощенного аналога для GetLastError |
Автор: FCM 20.8.2009, 11:05 |
Спасибо за ответы. Я имел в виду, почему такое исключение заявлено (в книге), но не отлавливается, написанной от руки SEH-ловушкой с EXCEPTION_ARRAY_BOUNDS_EXCEEDED . А есть ли разница между CRT и C++ RTL? _RTC_Initialize - это инициализация CRT? (Например, Visual Fortran при компоновке своих приложений использует стартовые функции CRT и SEH-обработчик с _XcptFilter, но он же не должен пользоваться С++ RTL?) Рихтер пишет про _CppUnhandledExceptionHandler (для последней "обработки" стандартных С++ исключений до "глобального" для данного потока UnhandledExceptionHandler ). Однако в crt0.c или в crtexe.c есть _XcptFilter, а _CppUnhandledExceptionHandler нет, а в в crtdll.c. есть _CppUnhandledExceptionHandler но нет _XcptFilter. Как же реально это выглядит после компоновки приложения? Охватывает ли SEH c _CppUnhandledExceptionHandler SEH c _XcptFilter? Еще есть вопрос по функции _matherr , которая , будучи определенной пользователем в исходнике с программой, сама проявляет себя в некоторых критических ситауциях - как ей это удается, с помощью того же SEH или по-другому? (Связано ли это как-то с тем, что объявление _matherr содержится в crtexe.c ) |
Автор: GremlinProg 20.8.2009, 12:35 | ||||||||||
проблема отлова такого исключения в том, что при затирании окружения массива может затереться сама запись SEH, она же находится так же, в стеке, просто чуть выше самого массива, поэтому будет довольно рисковано пытаться пройти по адресу этого обработчика это скорее всего инициализация счетчиков ошибок времени исполнения (RTC - Run-Time Error Checking): http://msdn.microsoft.com/en-us/library/w68b74dy.aspx CRT - изначально к С++ не относится ( C run-time library (without iostream or standard C++ library) ): http://msdn.microsoft.com/en-us/library/abx4dbyh.aspx _CppUnhandledExceptionHandler - это я так понимаю встроенный обработчик от MSVC, для фортрана может быть свой обработчик: названия могут различаться, это же просто callback, который регистрируется через SetUnhandledExceptionFilter а какая разница? это же по сути - финальный фильтр исключений, если его не ставить, то будет работать встроенный UnhandledExceptionFilter, который уже покажет окно с ошибкой с возможностью дальнейшей отладки приложения встроенным отладчиком (правда это можно перекрыть, выставив SEM_NOGPFAULTERRORBOX).
ну тут вариантов не так много, конечно SEH, только она не будет работать, если маскировать контрольное слово FPU-исключений, но это в принципе и так понятно
да, отчасти:
т.е. пользовательский _matherr перекрывает встроенный, а встроенный, по-идее, должен просто возвращать 0, т.е. разрешить отображать окно с fpu-ошибкой, достаточно поставить в самом верху один SEH-фрейм на эти 6 исключений и всегда вызывать _matherr, независимо от того, пользовательская она или встроенная, т.е. без лишних наворотов с регистрацией обработчика реализуется FPU-сторож |
Автор: FCM 21.8.2009, 11:58 | ||
Я тут попробовал в одной программе, где просто просматривал статусное слово при FLT-операциях, менять контрольное слово (отключать FPU "обработку" тех или иных FLT-ошибок) и ловить и диагностировать их с помощью SEH. Обнаружилась странная штука: если в ходе операции возникает одно исключение (например FLT_DIVIDE_BY_ZERO), то ловится все отлично, но если операция сопровождается 2-мя исключениями (например, при (упрощенный фрагмент)
возникает Overflow и Inexact), то ситуация странная, с одной стороны, до внешних обрабочиков (которые останавливают программу при остутствии моего SEH) дело не доходит, но и мой обработчик тоже реально не выполняется - программа прекращает выполнение в месте возникновения исключения. Я пробовал вложенные обработчики с фильтрами, настроенными непосредственно на вышеуказанные исключения - тоже не попадаю в тело обработчика и не получаю окошко от внешних (финальных) обработчиков (- программа прекращает выполнение в месте возникновения исключения.). |
Автор: GremlinProg 21.8.2009, 12:37 | ||
этого кода я не понял, если ты хотел включить какое-то исключение, то во втором параметре нужно использовать не арифметические, а побитовые операции:
вот так я четко размаскировал только одно исключение, не затронув остальные, т.е. включил SEH только для _EM_OVERFLOW можешь проверить ps: _controlfp_s( &ctrl, 0, 0 ) вернет текущее слово управления FPU |
Автор: GremlinProg 21.8.2009, 14:28 | ||
для включения сразу нескольких исключений все аналолгично:
|
Автор: FCM 21.8.2009, 17:38 | ||||
Там у меня опечатка (вследствие упрощения исходного текста)- должно быть int ctrl = _controlfp( _CW_DEFAULT - _EM_OVERFLOW- _EM_INEXACT , _MCW_EM); где _CW_DEFAULT согласно float.h равен сумме кодов fp-исключений и кое-чего еще
Поэтому записи вида _CW_DEFAULT-_EM_OVERFLOW или _CW_DEFAULT-_EM_OVERFLOW - _EM_INEXACT в функции _controlfp в принципе корректны (им наплевать на текущее контрольное слово они берут максимальную маску и отнимают код(ы) исключения, которое FPU должен сгенерить), хотя менее професcиональны чем побитовый вариант. В любом случае я просматриваю контрольное слово в двоичном формате и вижу, что сработало. Вопрос был немного в другом. в ходе операции float r = d; возникает два исключения OVERFLOW и INEXACT (я их виже просматривая статусное слово) и мой пользовательский SEH-обработчик не может сам полноценно ухватить это "двойное" исключение, и кроме того мешает внешним SEН обработчикам (от OC) вывести соотв. окошко (с кодом зафиксированного исключения). ( Или это фокусы компилятора MSVC7?). |
Автор: GremlinProg 21.8.2009, 18:50 | ||
покажи содержимое регистра SR, т.к. я вупор не вижу двух одновременных исключений со всеми твоими параметрами, статус XX88 задает поднятые: третий и седьмой биты регистра SR, которые говорят только о переполнении (INEXACT - это пятый бит, нумерация бит - с нуля) |
Автор: FCM 21.8.2009, 19:52 |
Как просмотреть регистр я не знаю. Я вывожу текущее контрольное слово до моих установок имею в двоичном формате 1001 0000 0000 0001 1111 после моих установок с изменением маски для Overflow и Inexact 1001 0000 0000 0001 1010 где 1000 0000 0000 0000 0000 - denormal 1 0000 - invalid 1000 - zerodivide 100 - overflow 10 - underflow 1 - inexact |
Автор: GremlinProg 21.8.2009, 20:38 |
контрольное слово вообще ни чего не говорит о произошедших исключениях, ты в этом слове только маскируешь прерывания, которые должны произойти реально, произощедшие исключения можно посмотреть в первых восьми битах слова статуса - SR под отладчиком просто открой вкладку "регистры" и добавь к ним FPU в MSVC соответствие регистров такое: CR - это CTRL SR - это STAT вот в STAT и смотри |
Автор: FCM 22.8.2009, 07:32 |
Забыл написать, что я и статусное слово тоже просматриваю (с помощью __statusfp) и вижу при вышеуказанных действиях: 101 (левые нулевые биты не отображаю) В отладчике тоже посмотрю. |
Автор: FCM 22.8.2009, 09:38 |
1) Кажется я понял в чем дело. Я запускал в Debug-сборке через Ctrl+F5 (запуск без отладки) и получал то, что получал. Если я запускаю в Debug через F5, то попадаю в свои ловушки, а поскольку в них только вывожу информацию, то в итоге получаю в окошечке внизу : First_chance exception и далее описание и код исключения. В Releas'e попадаю в свои ловушки, как и должно быть. Интересно, в чем фишка с Ctrl+F5 (запуск без отладки) - какие-то "подводные камни"? 2) Если открыть окошко Debug/Exceptions, то видим 4 или 5 (в МVС9) групп исключений. Последняя Win32 как я понимаю - аппаратные; одна(в МVС7) или две (в МVС9) группы только для управляемого кода; одна группа для CRT ловушек. А что значит группа для С++ исключений?: _com_error _ATL::CAtlException CExeption std::exception void |
Автор: GremlinProg 22.8.2009, 09:42 | ||
вот сейчас получил 2 ошибки одновременно, но эти 2 ошибки выставляются в статусе только если отключены исключения, стоит только включить SEH на обе, и статус начинает говорить нам только об одной ошибке - переполнение, т.е. ни каких программных проблем тут нет, просто видимо команда перестает выполняться при обнаружении первого немаскированного исключения включи в CR только _EM_INEXACT и получишь оба флага поднятых ( _EM_OVERFLOW и _EM_INEXACT ) но бросается конечно же только одно исключение, для которого оно разрешено суть видимо в том, что первое действие fstp - это все же загрузка регистра, а уже второе - проверка его содержимого на точность Добавлено через 8 минут и 57 секунд
ну так, естественно, Ctrl+F5 независимо от сборки, не подключает отладчик к процессу вообще последние - это как раз SEH исключения то же самое, что и все остальные - это окно позволяет приостанавливать отладчик, если генерируется какое-то из этих исключений, на Release-сборку это не оказывает ни какого влияния (просто в дебаге удобно по-быстрому найти ошибку, не расставляя брейкпойнты) |
Автор: GremlinProg 22.8.2009, 09:57 |
не оказывает ни какого влияния вообще на любую сборку, запущенного вне отладчика |
Автор: FCM 23.8.2009, 08:47 |
Понятно, спасибо А вот применение signal - это только для установки дополнительных "пунктов" для _XcptFilter? Или что-то более универсальное? |
Автор: GremlinProg 23.8.2009, 11:15 | ||
в winxfltr.c описана реализация _XcptFilter и __CppXcptFilter а в crtdll.c, dllcrt0.c, crtexe.c, crt0.c - их использование разница между ними только в том, что __CppXcptFilter перехватывает только одно искусственное исключение 'msc'|0xE0000000, которое определяет С++ исключение с передачей в нем экземпляра класса (по сути - это враппер над _XcptFilter) а _XcptFilter обрабатывает сразу серию исключений из _XcptActTab:
вот по этой таблице и определяется, какой сигнал соответствует Win32-исключению signal и raise - видимо, приближение к юниксам, влияние signal может распространяться как на _XcptFilter, так и за его пределами (как например в abort) в пределах _XcptFilter, signal позволяет разделить и переопределить его встроенное поведение а все, что пропускает _XcptFilter идет уже на финальную обработку, стоящую где-то на уровне создания процесса, т.е., скорее всего, где-то в недрах загрузчика можно сказать, signal - универсальный обработчик исключений, правда только их небольшого набора и не всегда именно через SEH |
Автор: GremlinProg 23.8.2009, 12:06 |
вот тут, кстати описана одна особенность UnhandledExceptionFilter при работе под отладчиком: http://support.microsoft.com/kb/173652 + дополнения по финальным исключениям т.е. под отладчиком UnhandledExceptionFilter не вызывается вообще, так что лучше на него не полагаться, по крайней мере при разработке проекта |
Автор: Earnest 24.8.2009, 07:20 |
Да, это кстати хороший (трудно-обнаружаемый) способ обнаружения отладчика... (это к вопросу о защите программ). Пардон за ![]() |
Автор: FCM 27.8.2009, 14:09 |
_CppXcptFilter вызывается в crtdll.c. В crt0.c вызывается только к _XcptFilter. А какие из файлов crt0.c, crtexe.c, crtdll.c используются например для консольных приложений, dll-приложений? Есть ли какая-нибуль связь между _CppXcptFilter, _CppUnhandledExceptionFilter (упомянутой в книге Рихтера "windows via C++"), terminate()? |
Автор: GremlinProg 28.8.2009, 09:41 | ||
я вообще-то не нашел ни где _CppUnhandledExceptionFilter, ни в документации, ни в образах и объектных файлах, посмотри, правильно-ли написано название функции, либо дай конкретные координаты источника (страница, издание, рус/eng, либо конкретную главу/подглаву) можно только предположить, что это простой фильтр, который вне отладчика перехватывает исключение 'msc'|0xE0000000, извлекает из него объект типа exception и показывает диалог с сообщением от этого исключения, либо в книге был дан просто пример как реализовать UnhandledExceptionFilter для C++ исключений связь-то понятно, между ними и должна быть: UnhandledException - это тот же SEH, просто его ставит загрузчик, а переход из _CppXcptFilter в UnhandledExceptionFilter происходит, очевидно, если _CppXcptFilter вернет EXCEPTION_CONTINUE_SEARCH, либо в секции обработчика под фильтром _CppXcptFilter будет поднято новое исключение |
Автор: FCM 28.8.2009, 10:10 | ||
Немного неточно я указал название функции: Джеффри Рихтер, Кристоф Назар Windows via C/C++. Программирование на языке Visual C++. СПб 2008. В главе 25, стр 800 упоминается функция __CxxUnhandledExceptionFilter. 2) Там же далее (c.825) написано , что С++ исключения в Visual С++ реализуются с помощью SEH. Но непонятно, разве можно с помощью SEH сделать корреткную деструкцию объектов классов. Или он должен был написать, что С++ исключения реализуются через SEH, только в асинхронной модели С++ исключений (/EHa)? |