Structured Exception Handling (SEH) and C++ exception handling
C++ exception handling builds on top of the OS SEH support. If you are writing C++ code, it is recommended you use C++ exception handing since SEH does not know how to handle C++ objects properly.
For example, for below code:
#include "stdafx.h"
class MyClass
{
public:
~MyClass()
{
printf("Myclass dtor\r\n");
}
};
int _tmain(int argc, _TCHAR* argv[])
{
__try
{
printf("in __try block\r\n");
//create a auto object on the stack
MyClass obj1;
//attemp to write to memory address NULL to trigger AV
int* p;
p = 0;
*p = 10;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
printf("in handler block\r\n");
}
}
If we build the code with any of the three "Enable C++ Exceptions" options enabled (/EHa, /EHsc or /EHs, see https://msdn.microsoft.com/en-us/library/1deeycx5(VS.80).aspx), it fails with below error:
warning C4509: nonstandard extension used: 'wmain' uses SEH and 'obj1' has destructor
error C2712: Cannot use __try in functions that require object unwinding
If we set the "Enable C++ Exceptions" to no, the code compiles but destructor of obj1 does not get called.
If you want your C++ exception code to catch SEH exceptions, you need to build the code with /EHa. For example, for below code, if you build it with /EHa, the access violation can be catched and the destructor of obj1 will be called:
#include "stdafx.h"
class MyClass
{
public:
~MyClass()
{
printf("Myclass dtor\r\n");
}
};
int _tmain(int argc, _TCHAR* argv[])
{
try
{
printf("in __try block\r\n");
//create a auto object on the stack
MyClass obj1;
//attemp to write to memory address NULL to trigger AV
int* p;
p = 0;
*p = 10;
}
catch(...)
{
printf("in handler block\r\n");
}
}
The destructor of obj1 is called during stack unwind:
test.exe!MyClass::~MyClass
msvcr100d.dll!_CallSettingFrame
msvcr100d.dll!__FrameUnwindToStat
msvcr100d.dll!CatchIt
msvcr100d.dll!FindHandlerForForeignException
msvcr100d.dll!FindHandler
msvcr100d.dll!__InternalCxxFrameHandler
msvcr100d.dll!__CxxFrameHandler3
ntdll.dll!ExecuteHandler2
ntdll.dll!ExecuteHandler
ntdll.dll!_KiUserExceptionDispatcher
test.exe!wmain
test.exe!__tmainCRTStartup
test.exe!wmainCRTStartup
kernel32.dll!BaseThreadInitThunk
ntdll.dll!__RtlUserThreadStart
ntdll.dll!_RtlUserThreadStart
We can use _set_se_translator to "translate" SEH exceptions to C++ exceptions and handle them together in a consistent way, see https://msdn.microsoft.com/en-us/library/5z4bw5h5(VS.80).aspx
C++ exception does not support the EXCEPTION_CONTINUE_EXECUTION semantics, so if you want to catch the exception, handle it and then continue the execution from the instruction that causes the exceptions, you will need to mix C++ exception with SEH.
For /EHa, a means asynchronous since from the application's point of view, SEH exceptions (such as access violation, divide by zero, etc.) are asynchronous. C++ exceptions raised by throw statement are considered as synchronous.
From the OS perspective, although the OS handles interrupt and exceptions in a similar way (via the IDT table etc.), exceptions are considered synchronous, but interrupts are asynchronous.