Здравствуйте, MT, Вы писали:
MT>Можно ли перехватить фатальные ошибки вроде "Memory could not be read"?
[] MT>Но очевидно что не все ошибки перехватываются...
У Микрософта есть такая странная функция под названием _set_se_translator (см. в MSDN), которая позволяет преобразовывать структурное исключение Windows (см. SEH) в исключение C++.
Здравствуйте, <Аноним>, Вы писали:
А>Здравствуйте, MT, Вы писали:
MT>>Можно ли перехватить фатальные ошибки вроде "Memory could not be read"? А>[] MT>>Но очевидно что не все ошибки перехватываются...
А>У Микрософта есть такая странная функция под названием _set_se_translator (см. в MSDN), которая позволяет преобразовывать структурное исключение Windows (см. SEH) в исключение C++.
мы пользуемся SetUnhandledExceptionFilter — он практически все перехватывает, но у нас своя обработка ошибок, а так много статей есть и, в том числе в MSDN, о внутренностях SEH и как его подружить с CPP.
Здравствуйте, MT, Вы писали:
MT>Можно ли перехватить фатальные ошибки вроде "Memory could not be read"? MT>Пробовал так:
MT>
MT> try {
MT> } catch (...) {
MT> }
MT>
MT>Но очевидно что не все ошибки перехватываются...
Рассказываю (и показываю). То что вы называете фатальными ошибками на самом деле являются SEH-исключениями операционной системы (внимательно читаем Рихтера). Они возбуждаются в различных ситуациях, как то: доступ по неправильному адресу, переполнение стека, деление на нуль, ошибка сопроцессора и.т.д. Будучи неперехваченным, SEH-исключение вызывает появление хорошо известного окна с предложением впаять разработчику и принудительной остановки процесса. Как перехватывать такие исключения в C++. Метод __try __except обсуждать не буду, поскольку его использование в C++ программах -- это дурной тон и возможный конфликт с родными C++ исключениями. Наиболее простой подход -- использовать catch(...). Для того, чтобы это работало, необходимо правильно настоить компилятор. Насчет VC++ 6.0 не помню, а вот в 7.0/7.1 придётся повыделываться. Заходим на вкладочку свойств проекта C/C++ Code Generation. Там есть строчка Enable C++ exception. Смело ставим в этой строчке No. Дальше двигаемся в конец к секции Command Line. На соотвествующей вкладочке есть окошко, Additional Options. Вот здесь надо прописать /EHac. Почему так, спросите у Билла Гейтса. Чтобы жизнь была интересней и разнообразней, наверное. Не всё ж галочки в property tab мышкой переключать. В чем недостаток этого подхода -- невозможно определить тип исключения, и ,что более серьёзно, возникают проблемы с плавающей арифметикой. Имеется более усовершенствованный метод. Заключается он в использовании так называемого se транслятора. Вот примерный код.
Смысл в следующем. Вызовом функции _set_se_translator можно инсталировать функцию, которая будет получать управление в случае возникновения в текущем потоке SEH-исключения. Главное назначение этой функции -- получить код SEH-исключения, завернуть в подходящую обёртку и выбросить нормальное C++ исключение. Которое в дальнейшем можно поймать обычным catch. Коды этих исключений можно получить из windows.h, а описание -- в MSDN в статье про EXCEPTION_RECORD. Среди этих кодов есть семейство особо важных, связанных с плавающей точкой. При получении одного из этих кодов, надо делать маленькую дополнительную обработку. А именно, нужно командой fninit сбросить сопроцессор в нормальное состояние. Ну и загрузить подходящее слово управление. Иначе флаги исключений по-прежнему будут висеть в сопроцессоре, что вызовет возбуждение нового исключения при попытке его снова заюзать. Вообще, использование исключений сопроцессора -- это отдельный нетривиальный вопрос. Поскольку с ним связан целый рад фокусов, на которые можно напороться.
Здравствуйте, Шахтер, Вы писали:
Ш>Вообще, использование исключений сопроцессора -- это отдельный нетривиальный вопрос. Поскольку с ним связан целый рад фокусов, на которые можно напороться.
А интересно где нибудь можно по подробней про это почитать?
Здравствуйте, Шахтер, Вы писали:
Ш>Вот здесь надо прописать /EHac. Почему так, спросите у Билла Гейтса. Чтобы жизнь была интересней и разнообразней, наверное. Не всё ж галочки в property tab мышкой переключать.
Во-первых, мне кажется, что нужно выставлять /EHa. Вот, что говорит MSDN:
Use /EHa to specify the asynchronous exception handling model (C++ exception handling with structured exception handling exceptions).
Во-вторых, в VS8.0 контора Mr. Gates'а все-таки вынесла эту опцию на флажок.
Здравствуйте, Вадим Никулин, Вы писали:
ВН>Здравствуйте, Шахтер, Вы писали:
Ш>>Вот здесь надо прописать /EHac. Почему так, спросите у Билла Гейтса. Чтобы жизнь была интересней и разнообразней, наверное. Не всё ж галочки в property tab мышкой переключать.
ВН>Во-первых, мне кажется, что нужно выставлять /EHa. Вот, что говорит MSDN: ВН>Use /EHa to specify the asynchronous exception handling model (C++ exception handling with structured exception handling exceptions).
Это не противоречит тому, что я написал. Вот полная статья из MSDN.
/EH{s|a}[c][-]
This option specifies the model of exception handling to be used by the compiler.
Use /EHs to specify the synchronous exception handling model (C++ exception handling without structured exception handling exceptions). If you use /EHs, do not rely on the compiler to catch asynchronous exceptions.
Use /EHa to specify the asynchronous exception handling model (C++ exception handling with structured exception handling exceptions).
The /EHc option requires that /EHs, /EHa, or /GX is specified. It tells the compiler to assume that extern C functions never throw an exception.
The option can be cleared by the symbol -. For example, /EHsc- is interpreted as /EHs /EHc-, and is equivalent to /EHs.
В большинстве случаев, можно предположить, что C-функции исключений не выбрасывают. Задав опцию /EHc можно несколько ускорить код. Естественно, если вы предполагаете, что некоторые C-функции в вашем приложении могут выбросить исключение, например потому, что вы передаёте им в качестве параметров указатель, который может быть не валидным, то использовать этот флаг не стоит. Хотя на мой вкус, данный подход при проектировании приложений контрпродуктивен.
ВН>Во-вторых, в VS8.0 контора Mr. Gates'а все-таки вынесла эту опцию на флажок.
Здравствуйте, Sergey_BG, Вы писали:
S_B>Здравствуйте, Шахтер, Вы писали:
Ш>>Вообще, использование исключений сопроцессора -- это отдельный нетривиальный вопрос. Поскольку с ним связан целый рад фокусов, на которые можно напороться.
S_B>А интересно где нибудь можно по подробней про это почитать?
По сопроцессору -- документацию Intel. А как использовать их в конкретных задачах -- я сомневаюсь, что об этом можно что-то прочитать толковое. Не встречал. В 99,9% люди просто не знают или не задумываются об использовании мало-мальски нетривиальных свойств плавающей арифметики.
MT>>Можно ли перехватить фатальные ошибки вроде "Memory could not be read"?
Один нюанс, нужно иметь ввиду, что для одно и того же исключения эта функция может быть вызвана боллее одного раза, важно это скажем при логировании исключений.
Tom wrote:
> MT>>Можно ли перехватить *фатальные ошибки вроде "Memory could not be > read"*? > Один нюанс, нужно иметь ввиду, что для одно и того же исключения эта > функция может быть вызвана боллее одного раза, важно это скажем при > логировании исключений.
Портабельно — никак. Для Windows можно использовать SEH (см.
SetUnhandledExceptionFilter), для POSIX'ов можно перехватывать SIGSEGV.
Ш>Здравствуйте, MT, Вы писали:остановки процесса. Как перехватывать такие исключения в C++. Метод __try __except обсуждать не буду, поскольку его использование в C++ программах -- это дурной тон и возможный конфликт с родными C++ исключениями. Наиболее простой подход -- использовать catch(...). Для того, чтобы это работало, необходимо правильно настоить компилятор. Насчет VC++ 6.0 не помню, а вот в 7.0/7.1 придётся повыделываться. Заходим на вкладочку свойств проекта C/C++ Code Generation. Там есть строчка Enable C++ exception. Смело ставим в этой строчке No. Дальше двигаемся в конец к секции Command Line. На соотвествующей вкладочке есть окошко, Additional Options. Вот здесь надо прописать /EHac.
Поставил тебе хорошую оценку за туториал по _set_se_retranslator и минус( ) за "дурной тон" и /EHac.
Ты представь, что тебе наделает оптимизатор, если он будет ждать исключения от любой ассемблерной команды? Все оптимизации, которые он может провести, зная что данный участок кода не бросает исключения, он не сделает.
И почему "дурной тон"? У нас это ловится на самом верху в функции WinMain, там делается минидамп стека и предлагается отправить письмо в поддержку (ну и еще в сугубо системном коде написанном на "С++ без классов", практически на С) Что здесь "дурного" ?
Как раз _set_se_retranslator — это дурной тон, поскольку создаёт иллюзию у начинающего программиста, что после обработки исключения программа осталась в определённом состоянии. Нет, если уж выкинуто SEH, надо забыть про С++ и начать игру по другим правилам.
Правильно работающая программа — просто частный случай Undefined Behavior
Здравствуйте, _Winnie, Вы писали:
_W>Здравствуйте, Шахтер, Вы писали:
Ш>>Здравствуйте, MT, Вы писали:остановки процесса. Как перехватывать такие исключения в C++. Метод __try __except обсуждать не буду, поскольку его использование в C++ программах -- это дурной тон и возможный конфликт с родными C++ исключениями. Наиболее простой подход -- использовать catch(...). Для того, чтобы это работало, необходимо правильно настоить компилятор. Насчет VC++ 6.0 не помню, а вот в 7.0/7.1 придётся повыделываться. Заходим на вкладочку свойств проекта C/C++ Code Generation. Там есть строчка Enable C++ exception. Смело ставим в этой строчке No. Дальше двигаемся в конец к секции Command Line. На соотвествующей вкладочке есть окошко, Additional Options. Вот здесь надо прописать /EHac.
_W>Поставил тебе хорошую оценку за туториал по _set_se_retranslator и минус( ) за "дурной тон" и /EHac.
_W>Ты представь, что тебе наделает оптимизатор, если он будет ждать исключения от любой ассемблерной команды? Все оптимизации, которые он может провести, зная что данный участок кода не бросает исключения, он не сделает.
Проблема надуманая. Никаких помех оптимизации это не создаёт.
На самом деле, единственная разница, которая появляется -- компилятор оставит фреймы исключений в некоторых местах, где раньше он их выбрасывал.
_W>И почему "дурной тон"? У нас это ловится на самом верху в функции WinMain, там делается минидамп стека и предлагается отправить письмо в поддержку (ну и еще в сугубо системном коде написанном на "С++ без классов", практически на С) Что здесь "дурного" ?
Потому что это не стандартный С++. Кроме того, лучше унифицировать процесс обработки исключений.
_W>Как раз _set_se_retranslator — это дурной тон, поскольку создаёт иллюзию у начинающего программиста, что после обработки исключения программа осталась в определённом состоянии.
Начинающим программистам надо учиться. В том числе и работе с продвинутыми средствами.
_W>Нет, если уж выкинуто SEH, надо забыть про С++ и начать игру по другим правилам.
Это слишком сильное утверждение. Есть конкретные случаи, когда применение SEH оправдано.
Например, для перехвата исключений сопроцессора.
Здравствуйте, Шахтер, Вы писали:
Ш>Здравствуйте, _Winnie, Вы писали: _W>>Здравствуйте, Шахтер, Вы писали:
>Проблема надуманая. Никаких помех оптимизации это не создаёт. http://rsdn.ru/Forum/?mid=1469428&flat=0
Все зависит от приложения. Если мы пишем GUI-враппер для базы данных, то да, никаких проблем, да, конечно.
Ш>Потому что это не стандартный С++.
А _set_se_translator — стандартный?
Ну уж нет, я предпочту в программе явные ms-specific кейворды __try, чем молчаливое неправильное поведение на другой платформе.
>Кроме того, лучше унифицировать процесс обработки исключений.
Ну, он унифицирован дальше некуда. один __try на самом верху.
_W>>Как раз _set_se_retranslator — это дурной тон, поскольку создаёт иллюзию у начинающего программиста, что после обработки исключения программа осталась в определённом состоянии.
Ш>Начинающим программистам надо учиться. В том числе и работе с продвинутыми средствами. _W>>Нет, если уж выкинуто SEH, надо забыть про С++ и начать игру по другим правилам.
Ш>Это слишком сильное утверждение. Есть конкретные случаи, когда применение SEH оправдано.
Да, но пытаться им ловить и обрабатывать запись по левому указателю не тот случай, согласись.
Ш>Например, для перехвата исключений сопроцессора.
Во-первых, господин MT собирался перехватить >Можно ли перехватить фатальные ошибки вроде "Memory could not be read"
Во-вторых, "для перехвата исключений сопроцессора" это тоже называется "забыть про С++". Под рукой стандарта нет, но насколько я помню, деление на ноль/переполнение и тп. это implementation defined.
Правильно работающая программа — просто частный случай Undefined Behavior
Здравствуйте, Шахтер, Вы писали:
Ш>В большинстве случаев, можно предположить, что C-функции исключений не выбрасывают. Задав опцию /EHc можно несколько ускорить код. Естественно, если вы предполагаете, что некоторые C-функции в вашем приложении могут выбросить исключение, например потому, что вы передаёте им в качестве параметров указатель, который может быть не валидным, то использовать этот флаг не стоит. Хотя на мой вкус, данный подход при проектировании приложений контрпродуктивен.
Если не ошибаюсь, то
В большинстве случаев, можно предположить, что C-функции исключений не выбрасывают