March 17, 2006
"SetUnhandledExceptionFilter" and VC8
Many programs are setting an own Unhandled-Exception-Filter , for catching unhandled exceptions and do some reporting or logging (for example creating a mini-dump ).
Now, starting with VC8 (VS2005), MS changed the behaviour of the CRT is some security related and special situations.
The CRT forces the call of the default-debugger (normally Dr.Watson) without informing the registered unhandled exception filter. The situations in which this happens are the following:
- Calling abort if the abort-behaviour was set to
_CALL_REPORTFAULT
. This is the default setting for release builds! - Failures detected by security checks (see also Compiler Security Checks In Depth ) This is also enabled by default!
- If no invalid parameter handler was defined (which is the default setting) and an invalid parameter was detected (this is done in many CRT functions by calling
_invalid_parameter
).
So the conclusion is: The are many situations in which your user-defined Unhandled-Exception-Filter will never be called. This is a major change to the previous versions of the CRT and IMHO not very well documented.
The solution
If you don’t want this behavior and you will be sure that your handler will be called, you need to intercept the call to SetUnhandledExceptionFilter which is used by the CRT to disable all previously installed filters. You can achieve this for x86 with the following code:
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#ifndef _M_IX86
#error "The following code only works for x86!"
#endif
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(
LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
{
return NULL;
}
BOOL PreventSetUnhandledExceptionFilter()
{
HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll"));
if (hKernel32 == NULL) return FALSE;
void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");
if(pOrgEntry == NULL) return FALSE;
unsigned char newJump[ 100 ];
DWORD dwOrgEntryAddr = (DWORD) pOrgEntry;
dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far
void *pNewFunc = &MyDummySetUnhandledExceptionFilter;
DWORD dwNewEntryAddr = (DWORD) pNewFunc;
DWORD dwRelativeAddr = dwNewEntryAddr – dwOrgEntryAddr;
newJump[ 0 ] = 0xE9; // JMP absolute
memcpy(&newJump[ 1 ], &dwRelativeAddr, sizeof(pNewFunc));
SIZE_T bytesWritten;
BOOL bRet = WriteProcessMemory(GetCurrentProcess(),
pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten);
return bRet;
}
LONG WINAPI MyUnhandledExceptionFilter(
struct _EXCEPTION_POINTERS *lpTopLevelExceptionFilter)
{
// TODO: MiniDumpWriteDump
FatalAppExit(0, _T(“Unhandled Exception occured!”));
return EXCEPTION_CONTINUE_SEARCH;
}
int _tmain()
{
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
BOOL bRet = PreventSetUnhandledExceptionFilter();
_tprintf(_T(“Prevented: %d”), bRet);
abort(); // force Dr.Watson in release!
}
Before calling PreventSetUnhandledExceptionFilter
you must be sure that no other thread is running (or at least no other thread is trying to call SetUnhandledExceptionFilter
).
The trackback url for this post is http://blog.kalmbachnet.de/bblog/trackback.php/75/
Posted 1 year, 9 months ago by Rodrigo Strauss • • www • Reply
Comment Trackback URL : http://blog.kalmbachnet.de/bblog/trackback.php/75/402/
Posted 1 year, 9 months ago by Jochen Kalmbach • • • Reply
Comment Trackback URL : http://blog.kalmbachnet.de/bblog/trackback.php/75/403/
Posted 1 year, 9 months ago by Rodrigo Strauss • • www • Reply
Comment Trackback URL : http://blog.kalmbachnet.de/bblog/trackback.php/75/404/
Posted 1 year, 9 months ago by Paul Shmakov • • • Reply
Comment Trackback URL : http://blog.kalmbachnet.de/bblog/trackback.php/75/406/
Posted 1 year, 9 months ago by Jochen Kalmbach • • • Reply
Comment Trackback URL : http://blog.kalmbachnet.de/bblog/trackback.php/75/407/
Posted 1 year, 9 months ago by Paul Shmakov • • • Reply
Comment Trackback URL : http://blog.kalmbachnet.de/bblog/trackback.php/75/408/
Comments have now been turned off for this post