I have third-party static library built with Enable C++ Exceptions
set to No (/EH
flag not specified). What are the consequences to calling into it from code built with C++ exceptions enabled (/EHa
)? If a Structured Exception is thrown from within the library, will the function provided to _set_se_translator by the main application be reliably called? (My experiments show that it will, but just wondering if this is defined behavior).
Are there any other considerations when mixing /EH
exception handing models?
Calling into code which does not have exceptions enabled shouldn't produce any problems -- this is no different than calling an external C function or something of that nature.
Calling from code which does not have exceptions enabled (into exception enabled code) will probably not contain the correct stack unwinding semantics in the exception disabled code, which means you'll be breaking invariants of that code, unless it was specifically designed to work with exceptions. (For example, some libraries (e.g. ANTLR) allocate all memory in a block and have the user code free everything at once, allowing exceptions to be used without leaking even though they themselves do not use exceptions).
Raymond Chen has quite an article about the innards of how C++'s exception handling works on MSVC++. Long story short, it's built on top of Windows' SEH. Therefore it should behave similarly to what happens if you throw a SEH exception in e.g. C code. (However, I've not verified this myself)
According to the MSDN then one is allowed to mix /EHa and /EHsc:
The two exception handling models, synchronous and asynchronous, are fully compatible and can be mixed in the same application.
But there seems to an exception to this rule, and that is when passing exceptions from unmanaged (/EHsc) to managed (/clr). The managed codes catches all exceptions using structured exception handling (SEH), and this causes unmanaged destructors not to be called when unwinding the stack. There are different workarounds:
- Change the unmanaged code to use /EHa instead of /EHsc. This has the downside that catch(...) within unmanaged code suddenly will catch access violations and other crazy stuff.
Create try-catch block within the unmanaged code, and ensure that no exceptions are passed between the unmanaged world and the managed world.
2.1. Possible middle road is to ensure that no destructors are expected to be called when passing exception from unmanaged to managed world. Within the unmanaged code make a try-catch wrapper, and then in the catch-block rethrow the exception into the managed world.