2015-10-09 3 views
5

Я пытаюсь поймать все необработанные исключения в моем приложении, чтобы сохранить файл журнала, когда они возникают. Это 64-битное приложение Windows, скомпилированное с использованием Visual Studio 2013, написанное на C++. Для тестирования я использую проект C++ Win32 по умолчанию, сгенерированный VS.Нарушение прав доступа в Windows

Я занимаюсь всеми исключениями, зарегистрировав обработчик с помощью SetUnhandledExceptionFilter. Это отлично работает для/большинства/случаев, но не для всех. За исключением всех исключений throw() - n и большинства аппаратных исключений, таких как с плавающей запятой или нарушениями доступа. Код, который не вызывает обработчик:

std::vector<int> foo(5, 0); 
for (auto& f : foo) 
    foo.erase(foo.begin() + 1); 

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

Код выше запускает обработчик исключений.

Я также попытался использовать сигнал try/catch или catch SIGSEGV, но ни один из них не запускается с первым примером. сигналы прерывания/завершения не вызываются. Короче говоря, я никоим образом не уведомляюсь, когда это происходит.

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

EDIT: Я просто хочу, чтобы все было ясно. Я запускаю код в режиме деблокирования, а ошибка в первом примере не вызвана проверкой итератором вне границ, выполненной в режиме отладки.

EDIT2: Я включил простейший пример, я могу придумать консольное приложение win32. См. Его здесь: http://pastebin.com/8L1SN5PQ

Обязательно запустите его в режиме деблокирования без прикрепленного отладчика.

+0

Вам нужно найти исключения SEH. Это не случаи, когда применяются обычные исключения C++. –

+1

Я пробовал. Использование SEH __try/__, за исключением того, что SEH включен в Visual Studio, дает тот же результат. Первый пример не вызывает исключение, второе - делает. – Uberyon

+0

Поскольку, как говорит Ханс, это не очень хорошая идея, я больше не буду тратить время на то, чтобы помочь вам это сделать. Вместо этого: если вы отлаживаете, запустите приложение в сборке отладки и используйте средства для его отладки до тех пор, пока не будет ошибок. Если это живое приложение, и вы пытаетесь отладить случайный крах, подумайте о развертывании отладочной сборки или использовании телеметрических служб. – Ben

ответ

2

Эти ошибки во время выполнения обрабатываются по-разному, они не генерируют исключение SEH. Грубо классифицируется где-то между «ошибкой программирования» и «атакой вредоносного ПО». И примерно так же информативно, как непонятое исключение C++, если у вас нет подключенного отладчика, обработчик по умолчанию вызывает мгновенную смерть с помощью __fastfail().

Вам необходимо позвонить _set_invalid_parameter_handler() в функцию main(), чтобы изменить способ обработки.Вы можете выбросить исключение C++ в свой собственный обработчик или вызвать RaiseException(), чтобы вызвать обработчик catch-em-all или просто сообщить об этом прямо там. Поощряйте последнее, вы хотите, чтобы процесс всегда был прерван.

Остерегайтесь того, что ваш фрагмент не является лучшим примером. Это UB, когда вы создаете свою программу без включенной отладки итератора, например, сборка Release с настройками по умолчанию. UB не гарантирует, что вы получите исключение SEH. И если это произойдет, вам нужно будет очень тщательно написать свой фильтр исключительных ситуаций, он будет вызван с блокировкой кучи, все еще занятой так, что основной материал не может работать. Лучший способ - пробудить защитный процесс с именованным событием. Затем он берет мини-накопитель и завершает программу.

+0

Спасибо. Я пытался регистрации обработчика как это: «VOID _invalid_parameter ( \t сопзЬ wchar_t * выражение, \t Const wchar_t * функция, \t Const wchar_t * файл, \t беззнаковое целочисленное значение строки, \t uintptr_t Сохранилось \t) { \t MessageBox (NULL, то L "InvalidParameter", L "InvalidParameter", MB_OK); } " в WinMain с вызовом: " _set_invalid_parameter_handler (_inval id_parameter);» Однако поведение не изменилось. (т. е. обработчик, как представляется, не вызван). – Uberyon

+0

Работает нормально, когда я пытаюсь это сделать с опубликованным фрагментом. Убедитесь, что функция отладки итератора не была полезной, нажмите «Игнорировать», когда отображает диалоговое окно подтверждения. –

+0

Он работает в режиме отладки с прикрепленным для меня отладчиком. Но запуск в выпуске без отладчика - это то, где у меня проблемы. – Uberyon

0

Вы не видите исключение, потому что оно обрабатывается внутри C-средой. В частности, это проверка границ, а не нарушение прав доступа.

Запуск его в отладчике я считаю, что это строка 242 в vector:

  _DEBUG_ERROR("vector iterators incompatible"); 

который в конечном счете вызывает _CrtDebugReportW: https://msdn.microsoft.com/en-us/library/8hyw4sy7.aspx

Вы можете контролировать поведение _CrtDebugReportW с помощью _CrtSetReportMode.

Обратите внимание, что это не действует в режиме деблокирования, так как это проверки границ режима отладки.

+0

Спасибо. Я попытался установить «_set_error_mode (_OUT_TO_MSGBOX)»; в WinMain, но поведение остается неизменным. Есть ли что-то, что я делаю неправильно? – Uberyon

+0

@ user2953192 Извините _set_error_mode управляет различными типами ошибок. Мои извинения. В вашем случае вы хотите '_CrtSetReportMode' – Ben

Смежные вопросы