From 0691998e45610129a5077a4c43a4f675de0ec2d7 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Fri, 14 May 1999 18:21:55 +0000 Subject: [PATCH] Fixed a few bugs, and improved the exception macros (based on suggestions by Sergei Turchanov). --- include/wine/exception.h | 127 +++++++++++++++++++++++++++++++++-------------- win32/except.c | 13 +++-- 2 files changed, 98 insertions(+), 42 deletions(-) diff --git a/include/wine/exception.h b/include/wine/exception.h index 06607b4d695..4185461b50b 100644 --- a/include/wine/exception.h +++ b/include/wine/exception.h @@ -15,7 +15,7 @@ * * They should be used like this: * - * __TRY() + * __TRY * { * do some stuff that can raise an exception * } @@ -23,11 +23,11 @@ * { * handle the exception here * } - * __ENDTRY() + * __ENDTRY * * or * - * __TRY() + * __TRY * { * do some stuff that can raise an exception * } @@ -40,52 +40,86 @@ * * The finally_func must be defined with the WINE_FINALLY_FUNC macro. * - * Warning: you cannot use return, break, or continue inside a __TRY - * or __EXCEPT block. + * Warning: inside a __TRY or __EXCEPT block, 'break' or 'continue' statements + * break out of the current block. 'return' causes disaster and must + * never be used. * * -- AJ */ -#define __TRY() \ - do { __WINE_FRAME __f; int __state = -1; \ - while (__state != 2) switch(__state) \ - { case 0: /* try */ +/* Define this if you want to use your compiler built-in __try/__except support. + * This is only useful when compiling to a native Windows binary, as the built-in + * compiler exceptions will most certainly not work under Winelib. + */ +#ifdef USE_COMPILER_EXCEPTIONS + +#define __TRY __try +#define __EXCEPT(func,arg) __except((func)(GetExceptionInformation(),GetExceptionCode(),(arg))) +#define __FINALLY(func,arg) __finally { (func)(!AbnormalTermination(),(arg)); } +#define __ENDTRY /*nothing*/ + +#else /* USE_COMPILER_EXCEPTIONS */ + +#define __TRY \ + do { __WINE_FRAME __f; \ + int __first = 1; \ + for (;;) if (!__first) \ + { \ + do { #define __EXCEPT(func,arg) \ - __state = 2; break; \ - case -1: /* init */ \ - __f.frame.Handler = (PEXCEPTION_HANDLER)WINE_exception_handler; \ - __f.u.e.filter = (func); \ - __f.u.e.param = (LPVOID)(arg); \ - EXC_push_frame( &__f.frame ); \ - __state = setjmp( __f.u.e.jmp); \ - break; \ - case 1: /* except */ - -#define __ENDTRY() \ - __state++; break; \ - } \ - EXC_pop_frame( &__f.frame ); \ + } while(0); \ + EXC_pop_frame( &__f.frame ); \ + break; \ + } else { \ + __f.frame.Handler = (PEXCEPTION_HANDLER)WINE_exception_handler; \ + __f.u.e.filter = (func); \ + __f.u.e.param = (LPVOID)(arg); \ + EXC_push_frame( &__f.frame ); \ + if (setjmp( __f.u.e.jmp)) { \ + EXC_pop_frame( &__f.frame ); \ + do { + +#define __ENDTRY \ + } while (0); \ + break; \ + } \ + __first = 0; \ + } \ } while (0); #define __FINALLY(func,arg) \ - __state = 2; break; \ - case -1: /* init */ \ - __f.frame.Handler = (PEXCEPTION_HANDLER)WINE_finally_handler; \ - __f.u.f.finally_func = (func); \ - __f.u.f.param = (LPVOID)(arg); \ - EXC_push_frame( &__f.frame ); \ - __ENDTRY() + } while(0); \ + EXC_pop_frame( &__f.frame ); \ + (func)( TRUE, (LPVOID)(arg) ); \ + break; \ + } else { \ + __f.frame.Handler = (PEXCEPTION_HANDLER)WINE_finally_handler; \ + __f.u.f.finally_func = (func); \ + __f.u.f.param = (LPVOID)(arg); \ + EXC_push_frame( &__f.frame ); \ + __first = 0; \ + } \ + } while (0); -#define WINE_EXCEPTION_FILTER(func,arg) DWORD WINAPI func( EXCEPTION_POINTERS *__eptr, LPVOID arg ) -#define WINE_FINALLY_FUNC(func,arg) void WINAPI func( LPVOID arg ) -#define GetExceptionInformation() (__eptr) -#define GetExceptionCode() (__eptr->ExceptionRecord->ExceptionCode) +/* Dummy structure for using GetExceptionCode in filter as well as in handler */ +typedef struct +{ + union { struct { DWORD code; } e; } u; +} __WINE_DUMMY_FRAME; + +typedef DWORD (*CALLBACK __WINE_FILTER)(PEXCEPTION_POINTERS,__WINE_DUMMY_FRAME,LPVOID); +typedef void (*CALLBACK __WINE_FINALLY)(BOOL,LPVOID); +#define WINE_EXCEPTION_FILTER(func,arg) \ + DWORD WINAPI func( EXCEPTION_POINTERS *__eptr, __WINE_DUMMY_FRAME __f, LPVOID arg ) +#define WINE_FINALLY_FUNC(func,arg) \ + void WINAPI func( BOOL __normal, LPVOID arg ) -typedef DWORD (*CALLBACK __WINE_FILTER)(PEXCEPTION_POINTERS,LPVOID); -typedef void (*CALLBACK __WINE_FINALLY)(LPVOID); +#define GetExceptionInformation() (__eptr) +#define GetExceptionCode() (__f.u.e.code) +#define AbnormalTermination() (!__normal) typedef struct { @@ -96,6 +130,7 @@ typedef struct { __WINE_FILTER filter; LPVOID param; + DWORD code; jmp_buf jmp; } e; struct /* finally data */ @@ -111,18 +146,36 @@ extern DWORD WINAPI WINE_exception_handler( PEXCEPTION_RECORD record, EXCEPTION_ extern DWORD WINAPI WINE_finally_handler( PEXCEPTION_RECORD record, EXCEPTION_FRAME *frame, CONTEXT *context, LPVOID pdispatcher ); +#endif /* USE_COMPILER_EXCEPTIONS */ + static inline EXCEPTION_FRAME *EXC_push_frame( EXCEPTION_FRAME *frame ) { +#if defined(__GNUC__) && defined(__i386__) + EXCEPTION_FRAME *prev; + __asm__ __volatile__(".byte 0x64\n\tmovl (0),%0" + "\n\tmovl %0,(%1)" + "\n\t.byte 0x64\n\tmovl %1,(0)" + : "=&r" (prev) : "r" (frame) : "memory" ); + return prev; +#else TEB * teb = NtCurrentTeb(); frame->Prev = teb->except; teb->except = frame; - return frame; + return frame->Prev; +#endif } static inline EXCEPTION_FRAME *EXC_pop_frame( EXCEPTION_FRAME *frame ) { +#if defined(__GNUC__) && defined(__i386__) + __asm__ __volatile__(".byte 0x64\n\tmovl %0,(0)" + : : "r" (frame->Prev) : "memory" ); + return frame->Prev; + +#else NtCurrentTeb()->except = frame->Prev; return frame->Prev; +#endif } #endif /* __WINE_WINE_EXCEPTION_H */ diff --git a/win32/except.c b/win32/except.c index 26285b41425..c455143cd7f 100644 --- a/win32/except.c +++ b/win32/except.c @@ -110,14 +110,17 @@ DWORD WINAPI WINE_exception_handler( EXCEPTION_RECORD *record, EXCEPTION_FRAME * { __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame; - if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) + if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL)) return ExceptionContinueSearch; if (wine_frame->u.e.filter) { EXCEPTION_POINTERS ptrs; + __WINE_DUMMY_FRAME dummy; + ptrs.ExceptionRecord = record; ptrs.ContextRecord = context; - switch(wine_frame->u.e.filter( &ptrs, wine_frame->u.e.param )) + dummy.u.e.code = record->ExceptionCode; + switch(wine_frame->u.e.filter( &ptrs, dummy, wine_frame->u.e.param )) { case EXCEPTION_CONTINUE_SEARCH: return ExceptionContinueSearch; @@ -126,8 +129,8 @@ DWORD WINAPI WINE_exception_handler( EXCEPTION_RECORD *record, EXCEPTION_FRAME * case EXCEPTION_EXECUTE_HANDLER: break; default: - /* FIXME: should probably raise a nested exception here */ - return ExceptionContinueSearch; + MESSAGE( "Invalid return value from exception filter\n" ); + assert( FALSE ); } } RtlUnwind( frame, 0, record, 0 ); @@ -147,6 +150,6 @@ DWORD WINAPI WINE_finally_handler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *fr if (!(record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))) return ExceptionContinueSearch; - wine_frame->u.f.finally_func( wine_frame->u.f.param ); + wine_frame->u.f.finally_func( FALSE, wine_frame->u.f.param ); return ExceptionContinueSearch; } -- 2.11.4.GIT