Structured exception handling
Exceptions can be initiated by hardware or software, and can
occur anywhere in your code. Structured exception handling provides a single
mechanism for the handling of exceptions.
The execution of certain instruction sequences can result in exceptions that are
initiated by hardware. For example, an access violation is generated by the
hardware when a process attempts to read from or write to a virtual address to
which it does not have the appropriate access.
Conceptually we set up a protected code block enclosed in a __try
{ } __except() { } expression.
If execution of the code in the protected block provokes an exception, the
filter expression in the __except() expression
will be executed. This code should return one of the following values:
| EXCEPTION_EXECUTE_HANDLER | The system transfers control to the exception handler, and execution continues in the stack frame in which the handler is found. |
| EXCEPTION_CONTINUE_SEARCH | The system continues to search for a handler. |
| EXCEPTION_CONTINUE_EXECUTION | The system stops its search for a handler and returns control to the point at which the exception occurred. If the exception is noncontinuable, this results in an EXCEPTION_NONCONTINUABLE-_EXCEPTION error. |
All this values, and the other definitions mentioned in this manual are in the standard header file <seh.h>. Include this file in any code that uses structured exception handling.
Within the context of the filter expression you can use
several functions that can help you get more information about what happened.
The function
unsigned int GetExceptionCode(void);
returns the code for the current exception. The function
EXCEPTION_POINTERS *GetExceptionInformation(void);
will return a pointer to a global EXCEPTION_POINTERS
structure. That structure contains a pointer to an exception record where a
wealth of information is available to know what happened.
This structure is defined as follows:
typedef struct _EXCEPTION_POINTERS {
PEXCEPTION_RECORD ExceptionRecord;
PCONTEXT ContextRecord;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
This structure contains just two pointers, one to an exception record, and the other to a CONTEXT record with the state of the machine at the point of the exception. The run time of lcc-win32 arranges for securing this information in a static area at each exception. Note that this information is meaningful if (and only if) an exception is active. At the next exception the static area will be overwritten with new information from the new exception. If you want to preserve the data you should copy it somewhere else.
In the EXCEPTION_RECORD structure we find:
typedef struct _EXCEPTION_RECORD {
DWORD ExceptionCode;
DWORD ExceptionFlags; // Can be either zero (continuable exception), or EXCEPTION_NONCONTINUABLE.
struct _EXCEPTION_RECORD* ExceptionRecord;
PVOID ExceptionAddress; // Machine address of instruction that faulted
DWORD NumberParameters; // This two parameters are used by the RaiseException() function.
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD, *PEXCEPTION_RECORD;
| Code | Meaning |
| EXCEPTION_ACCESS_VIOLATION | The thread tried to read from or write to a virtual address for which it does not have the appropriate access. |
| EXCEPTION_ARRAY_BOUNDS_EXCEEDED | The thread tried to access an array element that is out of bounds and the underlying hardware supports bounds checking. |
| EXCEPTION_BREAKPOINT | A breakpoint was encountered. |
| EXCEPTION_DATATYPE_MISALIGNMENT | The thread tried to read or write data that is misaligned on hardware that does not provide alignment. For example, 16-bit values must be aligned on 2-byte boundaries; 32-bit values on 4-byte boundaries, and so on. |
| EXCEPTION_FLT_DENORMAL_OPERAND | One of the operands in a floating-point operation is denormal. A denormal value is one that is too small to represent as a standard floating-point value. |
| EXCEPTION_FLT_DIVIDE_BY_ZERO | The thread tried to divide a floating-point value by a floating-point divisor of zero. |
| EXCEPTION_FLT_INEXACT_RESULT | The result of a floating-point operation cannot be represented exactly as a decimal fraction. |
| EXCEPTION_FLT_INVALID_OPERATION | This exception represents any floating-point exception not included in this list. |
| EXCEPTION_FLT_OVERFLOW | The exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type. |
| EXCEPTION_FLT_STACK_CHECK | The stack overflowed or underflowed as the result of a floating-point operation. |
| EXCEPTION_FLT_UNDERFLOW | The exponent of a floating-point operation is less than the magnitude allowed by the corresponding type. |
| EXCEPTION_ILLEGAL_INSTRUCTION | The thread tried to execute an invalid instruction. This happens when a jmp to a data location was executed, or the return stack of a function was corrupted. |
| EXCEPTION_IN_PAGE_ERROR | The thread tried to access a page that was not present, and the system was unable to load the page. For example, this exception might occur if a network connection is lost while running a program over the network. |
| EXCEPTION_INT_DIVIDE_BY_ZERO | The thread tried to divide an integer value by an integer divisor of zero. |
| EXCEPTION_INT_OVERFLOW | The result of an integer operation caused a carry out of the most significant bit of the result. This never happens under the default run time but it could be implemented later in future versions of lcc-win32 |
| EXCEPTION_INVALID_DISPOSITION | An exception handler returned an invalid disposition to the exception dispatcher. Programmers using a high-level language such as C should never encounter this exception. |
| EXCEPTION_NONCONTINUABLE_EXCEPTION | The thread tried to continue execution after a noncontinuable exception occurred. |
| EXCEPTION_PRIV_INSTRUCTION | The thread tried to execute an instruction whose operation is not allowed in the current machine mode. This can be a consequence of stack corruption or jump to an invalid location. Lcc-win32 never uses privileged instructions in the compiled program. |
| EXCEPTION_SINGLE_STEP | A trace trap or other single-instruction mechanism signaled that one instruction has been executed. |
| EXCEPTION_STACK_OVERFLOW | The thread used up its stack. |
Example:
#include <seh.h>
#include <stdio.h>
int main(void) {
char *p = NULL;
int code;
__try {
*p = 0;
}
__except(code = GetExceptionCode(),EXCEPTION_EXECUTE_HANDLER) {
printf("Caught exception %#x\n",code);
} }
This will produce
Caught exception 0xC0000005