Freigeben über


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.