Подтвердить что ты не робот

Исключения, незаметно зажатые Windows, как обращаться вручную?

У нас возникли проблемы с 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: активация контекста деактивирована неактивен для текущей нити выполнения.

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

4b9b3361

Ответ 1

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

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

Решение состоит в том, чтобы обернуть ваш wndproc (или hookproc) с помощью try/except кадр".

Я отправил отчет об ошибках в 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 для исправления, которое вы можете установить если хотите.

Ответ 3

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

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

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

Ответ 4

У меня возникла эта же проблема, и я обнаружил, что это стало причиной ошибки 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-битную программу, эта проблема исчезает.

Ответ 5

ОТВЕТ В HINDSIGHT для тех, кто наткнулся на это позже.

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

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

Ответ 6

Вы можете заставить 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);

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

Ответ 7

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