Exceptions silently caught by Windows, how to handle manually?
Asked Answered
P

7

20

We're having problems with Windows silently eating exceptions and allowing the application to continue running, when the exception is thrown inside the message pump. For example, we created a test MFC MDI application, and overrode 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
}

You would expect a nasty error message when running the application, but you actually get nothing at all. The program appears to be running perfectly well, but if you check the output window you will see:

First-chance exception at 0x13929384 in Test.exe: 0xC0000005: Access violation writing location 0x00000000.
First-chance exception at 0x77c6ee42 in Test.exe: 0xC0150010: The activation context being deactivated is not active for the current thread of execution.

I know why I'm receiving the application context exception, but why is it being handled silently? It means our applications could be suffering serious problems when in use, but we'll never know about it, because our users will never report any problems.

Play answered 12/4, 2010 at 12:59 Comment(5)
Yes, Visual Studio 2008.Play
Ok, then see and try my answer below...Kironde
@Mark Ingram: Once an access violation has occured, it's probably a better idea for your process to fail fast. Continuing to run after an access violation leads to subtle memory corruption bugs. As a customer, I'd be much more forgiving of a crash every once in a while than of giving incorrect answers. Something to keep in mind :)Calypso
@Billy ONeal, the application is silently consuming the exception and then continuing. Through no choice of our own. What I'm trying to do is intercept the exception and handle it accordingly (the crash above should cause a hard fail, but it doesn't).Play
@Mark Ingram: Carry on then :)Calypso
P
11

After browsing similar questions I stumbled across this answer: OpenGL suppresses exceptions in MFC dialog-based application

"Ok, I found out some more information about this. In my case it's windows 7 that installs KiUserCallbackExceptionHandler as exception handler, before calling my WndProc and giving me execution control. This is done by ntdll!KiUserCallbackDispatcher. I suspect that this is a security measure taken by Microsoft to prevent hacking into SEH.

The solution is to wrap your wndproc (or hookproc) with a try/except frame."

I've filed a bug report with Microsoft, you can see their response here:
http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught-in-wndproc-messages

From Microsoft:

Thanks for the report. I've found out that this is a Windows issue, and there is a hot fix available. Please see http://support.microsoft.com/kb/976038 for a fix that you can install if you wish.

Play answered 12/4, 2010 at 14:29 Comment(2)
It's worth noting that in most cases the hotfix is pointless as your customers are unlikely to have installed it.Play
But at least there's hope that the fix will be rolled into a future Windows release / service pack. It beats "This behaviour is by design." :-)Typewrite
I
12

If you're running on an x64 OS you may have been bitten by this:

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

Or (less likely in this case), it may be this: http://blogs.msdn.com/b/oldnewthing/archive/2011/01/20/10117963.aspx

Improvisatory answered 2/2, 2011 at 13:28 Comment(2)
This is the correct answer, you are throwing an SEH exception inside a user-mode callbackPrudenceprudent
+1 for the reference to "How to turn off the exception handler that COM "helpfully" wraps around your server" blogs.msdn.com/b/oldnewthing/archive/2011/01/20/10117963.aspxPharmaceutical
P
11

After browsing similar questions I stumbled across this answer: OpenGL suppresses exceptions in MFC dialog-based application

"Ok, I found out some more information about this. In my case it's windows 7 that installs KiUserCallbackExceptionHandler as exception handler, before calling my WndProc and giving me execution control. This is done by ntdll!KiUserCallbackDispatcher. I suspect that this is a security measure taken by Microsoft to prevent hacking into SEH.

The solution is to wrap your wndproc (or hookproc) with a try/except frame."

I've filed a bug report with Microsoft, you can see their response here:
http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught-in-wndproc-messages

From Microsoft:

Thanks for the report. I've found out that this is a Windows issue, and there is a hot fix available. Please see http://support.microsoft.com/kb/976038 for a fix that you can install if you wish.

Play answered 12/4, 2010 at 14:29 Comment(2)
It's worth noting that in most cases the hotfix is pointless as your customers are unlikely to have installed it.Play
But at least there's hope that the fix will be rolled into a future Windows release / service pack. It beats "This behaviour is by design." :-)Typewrite
C
5

functions that may be of interest:

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

PS, be aware that SetUnhandledExceptionFilter() can be overriden by other dlls loaded into your .exe. eg, flash and nvidia direct3d do this. I use api hooking to cure this.

Conjoined answered 12/4, 2010 at 13:8 Comment(2)
Hi, thanks for the suggestions, but I've tried all 4 (on the line before the crash) and the exception still isn't caught.Play
just because you call SetUnhandledExceptionFilter right before the msg loop, doesn't mean that during the message loop a dll doesn't override it. suggest placing a breakpoint on SetUnhandledExceptionFilter() (in kernel32, not the call in your exe).Conjoined
A
4

I experienced this same issue, and found it was a result of this Microsoft bug: http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught-in-wndproc-messages

There’s a fix available from Microsoft, though deploying it is somewhat challenging if you have multiple target platforms:

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

Here's an article on the subject describing the behavior:

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

The issue is basically that Hardware exceptions in 32-bit programs are silently caught in the WndProc routine on 64-bit OSs, unless you send commands telling it not to. Microsoft has a hotfix for the issue that is required if you're running Vista SP2, but isn't required with Windows 7 SP1 (not sure about Win7 without the SP).

Even WITH the hotfix, you need to enable the correct behavior by setting a registry key or making some calls to the kernel to tell it your process expects hardware exceptions to crash when encountered during WndProc.

According to the PaulBetts link above, this was done for backwards compatibility with Windows Server 2003.

If you program is a 64-bit program, this issue goes away.

Amaranth answered 10/1, 2012 at 23:56 Comment(1)
Note that KB976038 is rolled into W7SP1, however you still need to enable the exception handling.Gerlachovka
P
4

You can force Windows to not ignore the exceptions with this code snippet (from Microsoft's Exceptions that are thrown from an application that runs in a 64-bit version of Windows are ignored) that you will put in your process code:

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

It may be you have to add also an unhandled exception filter: the filter acts like a "top level exception handler" that is like a topmost catch block. For extracting a programmer-friendly string from _EXCEPTION_POINTERS you can see 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;
}

You add the filter with:

::SetUnhandledExceptionFilter(my_filter);

and you have to do it in every threads of your process: while the previous snippet is per-process, the filter is per-thread.

Pharmaceutical answered 28/11, 2012 at 8:34 Comment(3)
I believe this only works if the user has a patch installed on their system? Not useful for those users who aren't using the hotfix.Play
@MarkIngram I am afraid that if the patch kb976038 is not installed on the user's computer (that means, apart other things, the right version of kernel32.dll) he will have no possibility to see your diagnostic messages in case of exception. See also the good answer by Brian at #2622700Pharmaceutical
Note that the 976038 hotfix mentioned above is rolled into Win7 SP1, and this SetProcessUserModeExceptionPolicy works to surface exceptions thrown inside of the message pump. These are not caught by C++ try/catch blocks, and require their own filter as @uvts_cvs outlines above.Gerlachovka
G
3

ANSWER IN HINDSIGHT for anyone who stumbles upon this later.

This was caused by a known issue in Windows http://support.microsoft.com/kb/976038 - make sure you're up to date, install the hotpatch if you need to, and mark your application as Windows 7 compatible. http://msdn.microsoft.com/en-us/library/dd371711%28v=vs.85%29.aspx

I've seen this with exception codes c015000f and c0150010.

Gastrulation answered 5/8, 2011 at 22:53 Comment(1)
I have encountered this problem. I have an exception (std::bad_alloc) that is thrown in my windows procedure callback method. So if my handler for WM_NCCREATE throws an exception, windows will swallow it. Cue crash later in a mysterious location....Man
K
-1

Your output looks like you're using Visual Studio...
If not forget about my answer.
You can specify which exceptions will be thrown normally, meaning that Visual Studio catches them and your progam stops where the access violation occurred. Do this in the Debug/Exceptions... menu. If you are not sure what to enable, just enable them all...

Kironde answered 12/4, 2010 at 13:21 Comment(1)
That's fine for when you are debugging it yourself, but no good when you've released the product to a customer.Play

© 2022 - 2024 — McMap. All rights reserved.