2010-04-12 1 views
20

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

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: контекст активации деактивируется не активен для текущего потока исполнения.

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

+0

Вы используете Visual Studio? –

+0

Да, Visual Studio 2008. –

+0

Хорошо, тогда посмотрите и попробуйте мой ответ ниже ... –

ответ

11

После просмотра подобных вопросов я наткнулся на этот ответ: OpenGL suppresses exceptions in MFC dialog-based application

«Хорошо, я узнал больше информации об этом . В моем случае это окно 7 , который устанавливает KiUserCallbackExceptionHandler в качестве обработчика исключений, перед вызовом моего WndProc и дают мне контроль исполнение . Это делается NTDLL! KiUserCallbackDispatcher. I подозрительных-й на этом - безопасность меры, предпринятые 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 за исправление, которое вы можете установить , если хотите.

+0

Спасибо за обновление! – RichieHindle

+1

Стоит отметить, что в большинстве случаев исправление бессмысленно, поскольку ваши клиенты вряд ли установили его. –

+1

Но, по крайней мере, есть надежда, что исправление будет перенесено в будущий выпуск Windows/пакет обновления. Это бьет «Это поведение по дизайну». :-) – RichieHindle

4

функции, которые могут быть интересны:

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

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

+0

Привет, спасибо за предложения, но я пробовал все 4 (на линии перед сбоем), и исключение все еще не поймано. –

+0

только потому, что вы вызываете SetUnhandledExceptionFilter прямо перед циклом msg, не означает, что в течение цикла сообщений dll не переопределяет его. предложите поместить контрольную точку в SetUnhandledExceptionFilter() (в kernel32, а не в вызове exe). – SteelBytes

-1

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

+0

Это нормально, когда вы отлаживаете его самостоятельно, но не хорошо, когда вы выпустили продукт для клиента. –

+0

Да, это правда. –

12

Если вы работаете на 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

+1

Это правильный ответ, вы бросаете исключение SEH в обратном вызове пользовательского режима –

+0

+1 для ссылки на «Как отключить обработчик исключений, который COM« помогает »обернуть вокруг вашего сервера» http://blogs.msdn.com/b/oldnewthing/archive/2011/01/20/10117963.aspx –

3

ОТВЕТ В 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.

+0

Я столкнулся с этой проблемой. У меня есть исключение (std :: bad_alloc), которое бросается в мой метод обратного вызова процедуры Windows. Поэтому, если мой обработчик для WM_NCCREATE выдает исключение, окна будут проглатывать его. Cue crash позже в таинственном месте .... –

4

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

Там в исправление от корпорации Майкрософт, хотя его развертывания является несколько сложным, если у вас есть несколько целевых платформ:

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-битная программа, эта проблема уходит.

+1

Обратите внимание, что KB976038 перевернут в W7SP1, однако вам все равно нужно включить обработку исключений. – holtavolt

2

Вы можете заставить систему не игнорировать исключения с этим фрагментом кода (от компании Microsoft Exceptions that are thrown from an application that runs in a 64-bit version of Windows are ignored), что вы поставите в коде процесса:

// 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); 
    } 
} 

Может быть, вы должны также добавить в unhandled exception filter: фильтр действует как «обработчик исключений верхнего уровня», который похож на самый верхний блок catch. Для извлечения программатора удобно строки из _EXCEPTION_POINTERS вы можете увидеть Is there a function to convert EXCEPTION_POINTERS struct to a string?

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

Вы добавляете фильтр:

::SetUnhandledExceptionFilter(my_filter); 

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

+0

Я считаю, что это работает только в том случае, если у пользователя установлен патч в их системе? Не полезно для тех пользователей, которые не используют исправление. –

+1

@MarkIngram Я боюсь, что если патч kb976038 не установлен на компьютере пользователя (что означает, кроме других вещей, правильную версию 'kernel32.dll'), он не будет иметь возможности видеть ваши диагностические сообщения в случае исключения , См. Также хороший ответ Брайана на http://stackoverflow.com/questions/2622200/exceptions-silently-caught-by-windows-how-to-handle-manually/8812322#8812322 –

+0

Обратите внимание, что исправление 976038, упомянутое выше, является перевернутый в Win7 SP1, и эта команда SetProcessUserModeExceptionPolicy работает над исключениями, которые выбрасываются внутри насоса сообщений. Они не пойманы блоками try/catch C++ и требуют, чтобы их собственный фильтр описывался в виде @uvts_cvs. – holtavolt