TL;DR
(Visual Studio 2019, Windows 10 (so far tested on 1809LTSC, because this is my dev machine)
- We have an out-of-process COM server
- We set
COMGLB_EXCEPTION_DONOT_HANDLE_ANY
- "Fatal" SEH exceptions are handled OK.
- "Non-Fatal" SEH exceptions, among these C++ excpetions, are randomly swallowed or handled by the COM/RPC runtime stack.
Does COMGLB_EXCEPTION_DONOT_HANDLE
_ANY
work reliably? Are there any additional settings?
Neccessary Background
When using COM, the RPC layer will catch (and possibly swallow) all Structured SEH Exceptions (which include C++ exceptions). Raymond explains this very well:
Historically, COM placed a giant try/except around your server’s methods. If your server encountered what would normally be an unhandled exception, the giant try/except would catch it and turn it into the error RPC_E_SERVERFAULT. It then marked the exception as handled, so that the server remained running ... Mind you, this was actually a disservice
Now there is a supposed solution, namely IGlobalOptions
with setting COMGLB_EXCEPTION_DONOT_HANDLE_ANY.
This is supposed to (to quote The Old New):
... then go ahead and let the process crash.” In Windows 7, you can ask for the even stronger COMGLB_EXCEPTION_DONOT_HANDLE_ANY, which means “Don’t even try to catch ‘nonfatal’ exceptions.”
You can even find this recommendation in the docs:
It's important for applications that detect crashes and other exceptions that might be generated while executing inbound COM calls, ... to set COMGLB_EXCEPTION_HANDLING to COMGLB_EXCEPTION_DONOT_HANDLE to disable COM behavior of catching exceptions.
And the option is explained as:
COMGLB_EXCEPTION_DONOT_HANDLE_ANY
:
- When set and a fatal exception occurs in a COM method, this causes the COM runtime to not handle the exception. (caveat A)
- When set and a non-fatal exception occurs in a COM method, this causes the COM runtime to create a Windows Error Reporting (WER) dump and terminate the process. Supported in Windows 7 and later. (caveat B)
And here's the thing
Neither of the above two statements is really accurate, but specifically for any non fatal exception, which C++ exceptions are, we get random behavior:
I have set up a simple client / server COM Test Program in VS2019 and intentionally generate an unhandled C++ exception: There are two modes at runtime, seemingly at random:
- Server is terminated by the COM/RPC stack and we get an ID 1000 entry in the event log with the exceptioncode
0xe06d7363
(and a WER dump is written). The client gets 0x800706BE HRESULT in this case.- This is the advertised behavior.
- Starting the client -> server a second (or third, ...) time, the C++ Exception DOES NOT terminate the server, and the client gets
0xe06d7363
as HRESULT for its server call. No event log entry written!
For those "fatal" SEH exceptions the termination happens reliably; but not for the non-fatal ones.
What is going on here?