2010-04-12 10 views
20

Stiamo riscontrando problemi con Windows che ignorano le eccezioni e consentono all'applicazione di continuare a funzionare, quando l'eccezione viene generata all'interno del message pump. Per esempio, abbiamo creato un test di applicazione MDI MFC, e sovrascritto OnDraw:Eccezioni catturate silenziosamente da Windows, come gestirle manualmente?

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 
} 

Ci si aspetterebbe un messaggio di errore brutto quando si esegue l'applicazione, ma in realtà ottenere nulla. Il programma sembra essere in esecuzione perfettamente bene, ma se si controlla la finestra di uscita si vedrà:

eccezione first-chance a 0x13929384 in Test.exe: 0xC0000005: Violazione di accesso scrittura posizione 0x00000000.
eccezione prima possibilità di 0x77c6ee42 in Test.exe: 0xC0150010: Il contesto attivazione in fase di disattivazione non è attivo per il thread corrente di esecuzione.

So perché sto ricevendo l'eccezione del contesto dell'applicazione, ma perché viene gestito in silenzio? Significa che le nostre applicazioni potrebbero riscontrare seri problemi quando sono in uso, ma non lo sapremo mai, perché i nostri utenti non segnaleranno mai alcun problema.

+0

Si sta utilizzando Visual Studio? –

+0

Sì, Visual Studio 2008. –

+0

Ok, quindi guarda e prova la mia risposta di seguito ... –

risposta

11

Dopo la navigazione domande simili mi sono imbattuto in questa risposta: OpenGL suppresses exceptions in MFC dialog-based application

"Ok, ho scoperto qualche informazione in più su questo . Nel mio caso si tratta di Windows 7 che installa KiUserCallbackExceptionHandler come gestore di eccezioni, prima di chiamare il mio WndProc e dandomi controllo di esecuzione . Questo viene fatto ntdll! KiUserCallbackDispatcher. ho sospettato ° a questo è una misura di sicurezza presa da Microsoft per impedire l'hacking in SEH.

La soluzione è di avvolgere il tuo wndproc (o hookproc) con un tentativo/eccetto il frame ."

ho depositato un bug report con Microsoft, è possibile vedere la loro risposta qui:
http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught-in-wndproc-messages

Da Microsoft:.

Grazie per il rapporto che ho scoperto che questo è un problema di Windows, e v'è una correzione rapida disponibili. si prega di consultare http://support.microsoft.com/kb/976038 per una correzione che è possibile installare se lo si desidera.

+0

Grazie per l'aggiornamento! – RichieHindle

+1

Vale la pena notare che nella maggior parte dei casi l'aggiornamento rapido è inutile in quanto è improbabile che i vostri clienti l'abbiano installato. –

+1

Ma almeno c'è la speranza che la correzione venga trasferita in un rilascio/service pack di Windows futuro. Batte "Questo comportamento è di progettazione". :-) – RichieHindle

4

funzioni che possono essere di interesse:

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

PS, essere consapevoli che SetUnhandledExceptionFilter() può essere sovrascritto da altre DLL caricate nel vostro exe. ad esempio, flash e nvidia direct3d fanno questo. Io uso l'hook delle API per curare questo.

+0

Ciao, grazie per i suggerimenti, ma ho provato tutti e 4 (sulla linea prima dello schianto) e l'eccezione ancora non viene catturata. –

+0

solo perché si chiama SetUnhandledExceptionFilter subito prima del ciclo msg, non significa che durante il ciclo del messaggio una dll non la sovrascriva. suggerisci di inserire un punto di interruzione su SetUnhandledExceptionFilter() (in kernel32, non nella chiamata nel tuo exe). – SteelBytes

-1

L'output sembra che si stia utilizzando Visual Studio ...
Se non si dimentica della risposta.
È possibile specificare quali eccezioni verranno generate normalmente, il che significa che Visual Studio le cattura e il programma si arresta dove si è verificata la violazione di accesso. Fatelo nel menu Debug/Exceptions .... Se non siete sicuri di cosa abilitare, basta abilitare tutti ...

+0

Va bene quando si esegue il debug da soli, ma non va bene quando si rilascia il prodotto a un cliente. –

+0

Sì, è vero. –

12

Se siete in esecuzione su un sistema operativo x64 potrebbe essere stato morso da questo:

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

Or (meno probabile in questo caso), può essere questo: http://blogs.msdn.com/b/oldnewthing/archive/2011/01/20/10117963.aspx

+1

Questa è la risposta corretta, stai lanciando un'eccezione SEH all'interno di una callback in modalità utente –

+0

+1 per il riferimento a "Come disattivare il gestore di eccezioni che COM" è utile "avvolge il tuo server" http://blogs.msdn.com/b/oldnewthing/archive/2011/01/20/10117963.aspx –

3

RISPONDI A HINDSIGHT per chi si imbatte in questo dopo.

Questo è stato causato da un problema noto in Windows http://support.microsoft.com/kb/976038 - assicurarsi di essere aggiornati, installare l'hotpatch se necessario e contrassegnare l'applicazione come compatibile con Windows 7. http://msdn.microsoft.com/en-us/library/dd371711%28v=vs.85%29.aspx

L'ho visto con codici di eccezione c015000f e c0150010.

+0

Ho riscontrato questo problema. Ho un'eccezione (std :: bad_alloc) che viene lanciata nel mio metodo di callback della procedura Windows. Quindi se il mio gestore per WM_NCCREATE genera un'eccezione, Windows lo inghiottirà. Cue si blocca in un secondo momento in un luogo misterioso .... –

4

ho sperimentato questo stesso problema, e lo abbiamo trovato era un risultato di questo bug Microsoft: http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught-in-wndproc-messages

C'è una correzione disponibile da Microsoft, anche se la distribuzione è un po 'difficile se si dispone di più piattaforme di destinazione:

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

Ecco un articolo sull'argomento che descrive il comportamento:

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

Il problema è fondamentalmente che le eccezioni hardware nei programmi a 32 bit vengono catturate silenziosamente nella routine WndProc su sistemi operativi a 64 bit, a meno che non si inviino comandi che gli dicono di non farlo. Microsoft ha un hotfix per il problema che è richiesto se si esegue Vista SP2, ma non è richiesto con Windows 7 SP1 (non sono sicuro di Win7 senza SP).

Anche con l'aggiornamento rapido, è necessario abilitare il comportamento corretto impostando una chiave di registro o effettuando alcune chiamate al kernel per indicare che il processo prevede l'arresto anomalo delle eccezioni hardware durante il rilevamento durante WndProc.

Secondo i PaulBetts link qui sopra, questo è stato fatto per la compatibilità all'indietro con Windows Server 2003.

Se Program è un programma a 64 bit, questo problema va via.

+1

Nota che KB976038 viene inserito in W7SP1, tuttavia è comunque necessario abilitare la gestione delle eccezioni. – holtavolt

2

È possibile forzare Windows per ignorare le eccezioni con questo frammento di codice (da di Exceptions that are thrown from an application that runs in a 64-bit version of Windows are ignored Microsoft) che metterete nel codice processo:

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

Può essere è necessario aggiungere anche un unhandled exception filter: il filtro agisce come un "gestore di eccezioni di livello superiore" che è come il blocco catch più in alto. Per l'estrazione di una stringa programmatore-friendly da _EXCEPTION_POINTERS potete vedere 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; 
} 

Si aggiunge il filtro con:

::SetUnhandledExceptionFilter(my_filter); 

e bisogna farlo in ogni thread di processo: mentre il frammento precedente è per-process, il filtro è per-thread.

+0

Credo che funzioni solo se l'utente ha una patch installata sul proprio sistema? Non utile per quegli utenti che non utilizzano l'aggiornamento rapido. –

+1

@MarkIngram Ho paura che se la patch kb976038 non è installata sul computer dell'utente (cioè, a parte, la giusta versione di 'kernel32.dll') non avrà la possibilità di vedere i messaggi diagnostici in caso di eccezione . Vedi anche la buona risposta di Brian a http://stackoverflow.com/questions/2622200/exceptions-silently-caught-by-windows-how-to-handle-manually/8812322#8812322 –

+0

Si noti che l'aggiornamento rapido 976038 di cui sopra è trasferito su Win7 SP1 e questo SetProcessUserModeExceptionPolicy funziona per superare le eccezioni generate all'interno del message pump. Questi non vengono catturati dai blocchi try/catch di C++ e richiedono il loro filtro come i profili @uvts_cvs sopra. – holtavolt

Problemi correlati