Mail Archives: cygwin/2002/08/29/21:23:14
The program that follows catches exceptions with gcc using win32 api. I
used gcc version 2.95.3-6 on mingw, 2.95.3-5 on cygwin; win32api version
1.5 on mingw, 1.5.1 on cygwin.
Although g++ supplies exception handling capability, and
<http://sources.redhat.com/ml/cygwin/1999-08/msg00362.html> and drmingw
<http://mefriss1.swan.ac.uk/~jfonseca/gnu-win32/software/drmingw/> provide
code to catch exceptions, I am porting a c app to mingw, and I didn't want
to require the package maintainer to include a lot of extra code that may
conflict with changes in gcc, nor did I want to have to compile in c++.
So what is attached uses only c, no new headers or macro definitions, and
only a few lines of extra code to implement what is essentially a
_try/_except construct.
My solution is pretty basic. I would advise against installing more than
one exception handler at a time using this technique, as there is no
provision for 'unwinding' the unused handlers.
Most of the ideas came from
<http://www.microsoft.com/msj/0197/exception/exception.htm>, but one
interesting thing... the return codes do not do what their names would
imply. (I think that this is because the win32 exception handling is
intimately intertwined with the microsoft c++ compiler. The codes that the
handler returns are codes that vc++ uses to return the results of the
_except filter. The vc++ exception handler itself returns values from the
enumerated type EXCEPTION_DISPOSITION . This however, is *not* part of the
win32 api, it is part of the compiler's implementation of seh.)
Here is what I found:
Return value #defined name
0 EXCEPTION_CONTINUE_SEARCH
Action: Returns to the statement that caused the exception and re-executes
that statement. (Causes an infinite loop of calling the exception handler
if the handler does not fix the problem)
1 EXCEPTION_EXECUTE_HANDLER
Action: Passes the exception to the win32 default handler (error box)
-1 EXCEPTION_CONTINUE_EXECUTION
Action: Returns an "invalid disposition" exception, indicating that this is
not a valid return value!!!
Anyway... here it is
***************** bare_bones_seh.c ************************
#include <windows.h>
#include <stdio.h>
#include <setjmp.h>
long *fault_addr;
int a;
long valid_memory_area = 10;
int *z = (int *) 0x12345678;
jmp_buf environment;
int error_val = -1;
/* This Handler shows how SEH can modify global variables
and/or registers of the faulting routine to "fix" an error
It also shows that more than one error can be handled in a single
exception handler */
int problem_fixing_seh(
struct _EXCEPTION_RECORD *ExceptionRecord,
void * EstablisherFrame,
struct _CONTEXT *ContextRecord,
void * DispatcherContext)
{
printf("You've raised exception number %#x\n",
ExceptionRecord->ExceptionCode);
if (ExceptionRecord->ExceptionFlags & 1) {
printf("Non-continuable error\n");
exit(1); }
switch (ExceptionRecord->ExceptionCode) {
case STATUS_INTEGER_DIVIDE_BY_ZERO :
fault_addr = (long *)
(ExceptionRecord->ExceptionInformation[1]);
printf("Divide by zero at addr=%#x\n", fault_addr);
/* fix the problem */
a = 5;
printf("But don't worry, it is fixed now\n");
return EXCEPTION_CONTINUE_SEARCH;
case EXCEPTION_ACCESS_VIOLATION :
fault_addr = (long *)
(ExceptionRecord->ExceptionInformation[1]);
printf("ACCESS VIOLATION at addr=%#x\n", fault_addr);
/* Make faulting frame's EAX register point to a valid memory area */
ContextRecord->Eax = (DWORD)&valid_memory_area;
printf("But don't worry, it is fixed now\n");
return EXCEPTION_CONTINUE_SEARCH;
default:
return EXCEPTION_EXECUTE_HANDLER; }
}
/* This handler uses longjmp to go back to the "except" clause */
int problem_skipping_seh(
struct _EXCEPTION_RECORD *ExceptionRecord,
void * EstablisherFrame,
struct _CONTEXT *ContextRecord,
void * DispatcherContext)
{
printf("You've raised exception number %#x\n",
ExceptionRecord->ExceptionCode);
if (ExceptionRecord->ExceptionFlags & 1) {
printf("Non-continuable error\n");
exit(1); }
if (ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
return EXCEPTION_EXECUTE_HANDLER;
fault_addr = (long *) (ExceptionRecord->ExceptionInformation[1]);
printf("ACCESS VIOLATION at addr=%#x\n", fault_addr);
longjmp(environment, error_val);
}
main(int argc, char *argv[])
{
DWORD handler;
int error_code;
setbuf(stdout, NULL);
printf("Loading the error fixing seh\n");
/* Simple structured exception catcher */
handler = (DWORD) problem_fixing_seh ;
asm("movl %0, %%eax\n\t"
"pushl %%eax": : "r" (handler): "%eax" );
asm("pushl %fs:0");
asm("movl %esp, %fs:0");
/* We have installed our handler */
/* Now generate a divide by zero exception */
/* The handler will replace a with the value 5
and then re-execute the offending division */
a = 0;
valid_memory_area = 10 / a;
printf("valid_memory_area = %d\n", valid_memory_area);
/* Now an invalid memory access exception */
/* The assembler code attempts to store a value (12)
in location 0h . Upon detecting the exception
the handler changes EAX to point to valid_memory_area */
asm("movl $0, %%eax\n\t"
"movl $12, (%%eax)"
: : : "%eax", "memory" );
printf("valid_memory_area = %d\n", valid_memory_area);
/* Now uninstall this seh */
asm("movl (%%esp), %%eax \n\t"
"movl %%eax, %%fs:0"
: : : "%eax");
asm("addl $8, %esp");
/* handler is uninstalled */
printf("Error fixing handler removed\n");
/* Now install a different handler that skips offending code */
handler = (DWORD) problem_skipping_seh ;
asm("movl %0, %%eax\n\t"
"pushl %%eax": : "r" (handler): "%eax" );
asm("pushl %fs:0");
asm("movl %esp, %fs:0");
/* We have installed our handler */
printf("Problem skipping SEH installed\n");
/* The longjmp call in the handler will return here,
placing a non-zero return value in setjmp */
error_code = setjmp(environment);
if (error_code != 0)
{
printf ("Skipping invalid memory access\n");
goto NoCanDo;
}
z = 0;
printf("Trying to write to memory location 0\n");
*z = 12;
NoCanDo:
/* Uninstall the seh */
asm("movl (%%esp), %%eax \n\t"
"movl %%eax, %%fs:0"
: : : "%eax");
asm("addl $8, %esp");
printf("FINISHED\n");
}
--
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
Bug reporting: http://cygwin.com/bugs.html
Documentation: http://cygwin.com/docs.html
FAQ: http://cygwin.com/faq/
- Raw text -