Исключения молча ловятся Windows, как обрабатывать вручную? - PullRequest
20 голосов
/ 12 апреля 2010

У нас возникли проблемы с тем, что Windows молча использует исключения и позволяет приложению продолжать работу, когда исключение выдается внутри модуля обработки сообщений. Например, мы создали тестовое приложение MFC MDI и переопределили OnDraw:

void CTestView::OnDraw(CDC* /*pDC*/)
{
    *(int*)0 = 0; // Crash

    CTestDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;

    // TODO: add draw code for native data here
}

Можно ожидать неприятного сообщения об ошибке при запуске приложения, но на самом деле вы ничего не получаете. Программа работает отлично, но если вы проверите окно вывода, то увидите:

Исключение первого шанса в 0x13929384 в Test.exe: 0xC0000005: Запись о нарушении доступа местоположение 0x00000000.
Исключение первого шанса в 0x77c6ee42 в Test.exe: 0xC0150010: контекст активации деактивирован не активен для текущего потока исполнения.

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

Ответы [ 7 ]

12 голосов
/ 02 февраля 2011

Если вы работаете в операционной системе x64, возможно, вас укусило это:

http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/

Или (менее вероятно в этом случае), это может быть так: http://blogs.msdn.com/b/oldnewthing/archive/2011/01/20/10117963.aspx

11 голосов
/ 12 апреля 2010

После просмотра похожих вопросов я наткнулся на этот ответ: OpenGL подавляет исключения в диалоговом приложении MFC

"Хорошо, я узнал больше информации об этом. В моем случае это Windows 7 который устанавливает KiUserCallbackExceptionHandler as обработчик исключений, перед вызовом моего WndProc и дает мне исполнение контроль. Это сделано Ntdll! KiUserCallbackDispatcher. я подозреваю, что это безопасность меры, принятые Microsoft для предотвращения взлом в SEH.

Решение - обернуть ваш wndproc (или hookproc) с попыткой / кроме кадр ".

Я отправил сообщение об ошибке в Microsoft, вы можете увидеть их ответ здесь:
http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught-in-wndproc-messages

От Microsoft:

Спасибо за отчет. Я узнал, что это проблема Windows, и есть исправление доступно. Посмотри пожалуйста http://support.microsoft.com/kb/976038 для исправления, которое вы можете установить если хочешь.

4 голосов
/ 11 января 2012

Я столкнулся с такой же проблемой и обнаружил, что это было результатом этой ошибки Microsoft: http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught-in-wndproc-messages

Существует исправление, доступное от Microsoft, хотя его развертывание несколько сложное, если у вас несколько целевых платформ:

http://support.microsoft.com/kb/976038

Вот статья на тему, описывающая поведение:

http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/

В основном проблема заключается в том, что аппаратные исключения в 32-разрядных программах автоматически перехватываются в подпрограмме WndProc в 64-разрядных ОС, если вы не отправляете команды, говорящие об этом. У Microsoft есть исправление для проблемы, которая необходима для , если вы используете Vista SP2, но не требуется для Windows 7 SP1 (не уверен в Win7 без SP).

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

Согласно приведенной выше ссылке PaulBetts, это было сделано для обратной совместимости с Windows Server 2003.

Если вы программируете 64-битную программу, эта проблема исчезнет.

4 голосов
/ 12 апреля 2010

функций, которые могут представлять интерес:

SetUnhandledExceptionFilter()
_set_invalid_parameter_handler()
_RTC_SetErrorFuncW()
_CrtSetReportHookW2()

PS, имейте в виду, что SetUnhandledExceptionFilter () может быть переопределен другими библиотеками, загруженными в ваш .exe. например, flash и nvidia direct3d делают это. Я использую api hooking, чтобы вылечить это.

3 голосов
/ 06 августа 2011

ОТВЕТИТЬ ЗА ОЗНАКОМЛЕНИЕМ за тех, кто сталкивается с этим позже.

Это было вызвано известной проблемой в Windows http://support.microsoft.com/kb/976038 - убедитесь, что вы в курсе, установите исправление, если вам нужно, и пометьте ваше приложение как совместимое с Windows 7. http://msdn.microsoft.com/en-us/library/dd371711%28v=vs.85%29.aspx

Я видел это с кодами исключений c015000f и c0150010.

2 голосов
/ 28 ноября 2012

Вы можете заставить Windows не игнорировать исключения с этим фрагментом кода (из Microsoft Исключения, которые вызываются из приложения, работающего в 64-разрядной версии Windows, игнорируются ), который вы вставите код вашего процесса:

// my SDK is v6.0A and the two APIs are not available in the .h files, so I need to get them at runtime
#define PROCESS_CALLBACK_FILTER_ENABLED     0x1
typedef BOOL (WINAPI *GETPROCESSUSERMODEEXCEPTIONPOLICY)(__out LPDWORD lpFlags);
typedef BOOL (WINAPI *SETPROCESSUSERMODEEXCEPTIONPOLICY)(__in DWORD dwFlags );
HINSTANCE h = ::LoadLibrary(L"kernel32.dll");
if ( h ) {
   GETPROCESSUSERMODEEXCEPTIONPOLICY GetProcessUserModeExceptionPolicy = reinterpret_cast< GETPROCESSUSERMODEEXCEPTIONPOLICY >( ::GetProcAddress(h, "GetProcessUserModeExceptionPolicy") );
   SETPROCESSUSERMODEEXCEPTIONPOLICY SetProcessUserModeExceptionPolicy = reinterpret_cast< SETPROCESSUSERMODEEXCEPTIONPOLICY >( ::GetProcAddress(h, "SetProcessUserModeExceptionPolicy") );
   if ( GetProcessUserModeExceptionPolicy == 0 || SetProcessUserModeExceptionPolicy == 0 ) {
      return;
   }
   DWORD dwFlags;
   if (GetProcessUserModeExceptionPolicy(&dwFlags)) {
      SetProcessUserModeExceptionPolicy(dwFlags & ~PROCESS_CALLBACK_FILTER_ENABLED); 
   }
}

Возможно, вам придется добавить фильтр необработанных исключений : фильтр действует как «обработчик исключений верхнего уровня», который похож на самый верхний блок catch. Для извлечения дружественной для программиста строки из _EXCEPTION_POINTERS вы можете увидеть Есть ли функция для преобразования структуры EXCEPTION_POINTERS в строку?

LONG WINAPI my_filter(_In_  struct _EXCEPTION_POINTERS *ExceptionInfo)
{
   ::OutputDebugStringA("an exception occured!");
   return EXCEPTION_EXECUTE_HANDLER;
}

Вы добавляете фильтр с помощью:

::SetUnhandledExceptionFilter(my_filter);

и вы должны делать это во всех потоках вашего процесса: в то время как предыдущий фрагмент - для каждого процесса, фильтр - для каждого потока.

0 голосов
/ 12 апреля 2010

Ваш вывод выглядит так, как будто вы используете Visual Studio ...
Если не забыть о моем ответе.
Вы можете указать, какие исключения будут выбрасываться в обычном режиме, что означает, что Visual Studio перехватывает их, и ваша программа останавливается там, где произошло нарушение доступа. Сделайте это в меню «Отладка / Исключения ...». Если вы не уверены, что включить, просто включите их все ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...