Structured and Standard C++ Exception Handling
eRTOS supports Standard exceptions (throw/catch), Windows Structured Exception Handling (SEH) APIs, and C frame-based exception handling (try/except/finally), all as defined by the Windows Platform SDK.
In this section:
- C++ Support
- Structured Exception Handling
- Differences Between Windows and eRTOS Exception Handling
- General User Notes for Exception Handling
C++ Support
eRTOS supports the Visual C++ language, with some restrictions discussed in the note below. eRTOS supports all C++ features usable in a Windows C++ eRTOS application, including new/delete operators and standard exception handling.
Note: eRTOS does not claim support for all C++ libraries. Support is limited to libraries that depend upon the set of Windows functions supported in the eRTOS environment.
Structured Exception Handling
eRTOS supports Structured Exception Handling and standard C++ exceptions, as described by the Windows Platform SDK, including:
- Windows Structured Exception Handling APIs, which include RaiseException, SetUnhandledExceptionFilter, UnhandledExceptionFilter, AbnormalTermination, GetExceptionCode, GetExceptionInformation
- Frame-based exception handlers: try-except and try-finally.
- Standard C++ exception handling: try-throw-catch.
- Handling hardware exceptions with the following Windows exception codes:
EXCEPTION_BREAKPOINT
EXCEPTION_SINGLE_STEP
EXCEPTION_ACCESS_VIOLATION EXCEPTION_ILLEGAL_INSTRUCTION EXCEPTION_FLT_DENORMAL_OPERAND EXCEPTION_FLT_DIVIDE_BY_ZERO EXCEPTION_FLT_INEXACT_RESULT EXCEPTION_FLT_INVALID_OPERATION EXCEPTION_FLT_OVERFLOW EXCEPTION_FLT_UNDERFLOW EXCEPTION_INT_DIVIDE_BY_ZEROEXCEPTION_DOUBLE_FAULT
Using Structured Exception Handling
To use Structured Exception Handling (SEH) in an eRTOS application, the application must be linked with the Microsoft C Runtime libraries which contain run-time support for the SEH frame-based exception handlers.
Differences Between Windows and eRTOS Exception Handling
The eRTOS implementation follows Windows SEH semantics where possible. This section describes the differences.
UnhandledExceptionFilter
On an unhandled exception, eRTOS always displays a statement that the application has been frozen. You can use Kill to terminate the frozen application.
Exception caused by a thread
When a thread of a multithreaded application causes an exception in Windows, the system displays a dialog box. Until the user responds to the box, other threads of the application continue running. Once the user has responded, all threads of the application terminate.
eRTOS acts differently for unhandled exceptions; it freezes all threads of a process whenever any of them gets an unhandled exception, and prints an informational statement on the console. This behavior is safer and more intuitive in the eRTOS context. You can, however, emulate the Windows behavior by using per-thread unhandled exception filter functions.
Continue execution context
When an exception occurs in the __try guarded area, and if the filter modifies the FPU state and responds with continue execution, the continue execution context for FPU is different between Windows and eRTOS. In this case, Windows resets the FPU state while eRTOS restores the FPU state captured at the start of dispatching the exception handling logic.
Nested exceptions and collided unwinds
eRTOS follows Windows rules for nested exceptions and "collided" unwinds, with this minor difference:
- Non-continuable exceptions — Non-continuable exceptions caused by the program directly or by exception handling run-time itself. Windows repeatedly re-asserts those; but repeated re-assertion of exceptions consumes stack space. A stack fault in eRTOS causes a system crash or instability. For robustness, eRTOS freezes the process that generated a non-continuable exception.
- Hardware exceptions — eRTOS exception codes for hardware exceptions are tied to x86/x64 interrupt and exception codes (refer to Interrupt and Exception Handling in Intel® Developer’s Manual), thus differing from Windows exception codes caused by similar errors. For example, an errant Windows application gets an EXCEPTION_ACCESS_VIOLATION as defined by Windows, an eRTOS application gets EXCEPTION_PAGE_FAULT. A Windows EXCEPTION_ILLEGAL_INSTRUCTION is equivalent to the eRTOS code EXCEPTION_INVALID_OPCODE.
General User Notes for Structured Exception Handling
- Structured exception handling is a powerful mechanism with often subtle semantics. It is quite easy to write code that causes infinite re-assertion of an exception. For example, if a filter expression always faults, or always dismisses a hardware exception which gets re-executed, the process continues generating exceptions until it overflows the stack. Miscasting the handler argument to SetUnhandledExceptionFilter may be equally fatal.
- Because stack faults in eRTOS cause system crash or instability, you must be careful when writing exception handlers. Testing your application in Windows is recommended to avoid stack overflows in eRTOS.
- If eRTOS Structured Exception Handling (SEH) wants to access and modify floating point or processor extended registers within the CONTEXT record, the SEH filter and except body should access and modify the FltSave or XState field of CONTEXT. The FltSave field contains the processor legacy FPU/SSE state registers with the FXSAVE format. The XState field contains the processor AVX/AVX512/AMX/MPX, etc. extended state registers with the XSAVE format (starting from XSAVE Header), which is available in winnt.h.
- The /EHa compiler option enables safe stack unwinding for both asynchronous exceptions and C++ exceptions. It supports handling of both standard C++ and structured exceptions by using the native C++ catch(...) clause. However, specifying /EHa and trying to handle all exceptions by using catch(...) can be dangerous. In most cases, asynchronous exceptions are unrecoverable and should be considered fatal. Catching them and proceeding can cause process corruption and lead to bugs that are hard to diagnose and fix.
- If you use SEH in a C++ program that you compile by using the /EHa or /EHsc option, destructors for local objects are called, but other execution behavior might be unexpected. In most cases, instead of SEH, we recommend that you use Standard C++ exception handling. This ensures your code is more portable and can handle exceptions of any type.