I have a situation where an application which uses SetUnhandledExceptionFilter (via google breakpad ) to set up a custom exception handler is hanging after the breakpad exception handler has caught a crash, saved a minidump file and returned EXCEPTION_EXECUTE_HANDLER from the SetUnhandledExceptionFilter function, to execute the standard exception handler. The hang also happens if the filter function returns EXCEPTION_CONTINUE_SEARCH and the Windows Error Report dialog has been disabled via SetErrorMode(). If SetErrorMode() is not used to disable WER, the process closes once the user clicks the 'Close' button in the WER dialog.
The hang happens under Windows XP but not Windows 7.
The documentation for SetUnhandledExceptionFilter states that when 'EXECEPTION_EXECUTE_HANDLER' is returned, the associated exception handler will execute which "usually results in process termination," but I couldn't find documentation of the termination method used.
A stack trace shows that the hang is occurring in a global destructor for an object in a 3rd party DLL, called from the DllMain() prelude.
ntdll.dll!_KiFastSystemCallRet@0()
ntdll.dll!_NtWaitForSingleObject@12() + 0xc bytes
kernel32.dll!_WaitForSingleObjectEx@12() + 0x8b bytes
kernel32.dll!_WaitForSingleObject@8() + 0x12 bytes
QtCore4.dll!QWaitCondition::wait(QMutex * mutex=0x03ad1b00, unsigned long time=4294967295) Line 175 + 0x15 bytes C++
QtCore4.dll!QThreadPoolPrivate::waitForDone() Line 295 + 0x10 bytes C++
QtCore4.dll!QThreadPool::~QThreadPool() Line 429 C++
QtCore4.dll!QThreadPool::`vector deleting destructor'() + 0x3d bytes C++
QtCore4.dll!`theInstance'::`8'::`dynamic atexit destructor for 'cleanup''() + 0x14 bytes C++
QtCore4.dll!_CRT_INIT(void * hDllHandle=0x02b2b2d0, unsigned long dwReason=45265416, void * lpreserved=0x02b2b208) Line 446 C
QtCore4.dll!__DllMainCRTStartup(void * hDllHandle=0x67000000, unsigned long dwReason=0, void * lpreserved=0x00000000) Line 557 + 0x8 bytes C
QtCore4.dll!_DllMainCRTStartup(void * hDllHandle=0x67000000, unsigned long dwReason=0, void * lpreserved=0x00000001) Line 507 + 0xe bytes C
ntdll.dll!_LdrpCallInitRoutine@16() + 0x14 bytes
ntdll.dll!_LdrShutdownProcess@0() - 0xfe bytes
kernel32.dll!__ExitProcess@4() + 0x42 bytes
kernel32.dll!7c81cb0e()
kernel32.dll!_BaseThreadStart@8() + 0x2f479 bytes
I guess that the mutex was locked by a thread that has since been killed, but I can imagine other kinds of global ctors/dtors that might be executed in this way that would cause a similar problem. My questions are:
- Is it expected behavior that
ExitProcess()
is called in the event of a crash if WER is disabled viaSetErrorMode()
? - Does anyone know of a change in behavior of the default exception handlers between Windows XP and Windows 7 which might be relevant?
- If
ExitProcess()
is expected behavior, what is the safest way to deal with this problem in third-party DLLs? CallingTerminateProcess()
from the breakpad exception handler fixes the problem but are there any caveats I should be aware of?
To answer "What has changed between XP and Windows 7," the following could be relevant: "The case of the disappearing OnLoad exception – user-mode callback exceptions in x64," http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/.