At this point, I've made quite a mess of some of these files w.r.t. indentation (I'm a two-spaces guy, but the authors of some files I'm changing use four). Will fix in seh_try_macros-NOOP-04.diff. After that, I guess I'm done with SEH for now until I figure out what to do about re-raising in __finally. LICENSE: X11/Bugroff CHANGELOG: * dlls/ntdll: exception.c, ntdll.spec; dlls/ntdll/tests: seh_macros.c; include/wine: exception.h: Greg Turner <gmturner007@ameritech.net> - Fix a broken test, and avoid compiler-optimization bugs (hopefully exposed only by the trivial nature of the test code) that allowed the test to pass previously. - some "performance" improvements (from slower to slow). - add __leave support and some tests. -- diff -ur -x CVS -x 'bigdif*' -x autom4te.cache ../wine.test/dlls/ntdll/exception.c ./dlls/ntdll/exception.c --- ../wine.test/dlls/ntdll/exception.c 2003-01-13 19:29:54.000000000 -0600 +++ ./dlls/ntdll/exception.c 2003-01-13 19:31:39.000000000 -0600 @@ -67,7 +67,7 @@ wine_seh_f_data *wine_SEH_FData; static DWORD wine_seh_f_tls_index = -1; -void wine_init_thread_seh_f() +inline void wine_init_thread_seh_f() { if (wine_seh_f_tls_index == -1) if ((wine_seh_f_tls_index = TlsAlloc()) == -1) assert(FALSE); @@ -106,6 +106,12 @@ return wine_SEH_FData->stackdata[--wine_SEH_FData->stackdepth]; } +void __wine_inc_seh_f_loop() +{ + wine_init_thread_seh_f(); + wine_SEH_FData->loop++; +} + extern void SIGNAL_Unblock(void); void WINAPI EXC_RtlRaiseException( PEXCEPTION_RECORD, PCONTEXT ); diff -ur -x CVS -x 'bigdif*' -x autom4te.cache ../wine.test/dlls/ntdll/ntdll.spec ./dlls/ntdll/ntdll.spec --- ../wine.test/dlls/ntdll/ntdll.spec 2003-01-13 19:29:54.000000000 -0600 +++ ./dlls/ntdll/ntdll.spec 2003-01-13 17:24:50.000000000 -0600 @@ -1031,6 +1031,7 @@ @ cdecl -norelay __wine_exception_handler(ptr ptr ptr ptr) __wine_exception_handler @ cdecl -norelay __wine_finally_handler(ptr ptr ptr ptr) __wine_finally_handler @ cdecl -norelay __wine_get_seh_f_loop() __wine_get_seh_f_loop +@ cdecl -norelay __wine_inc_seh_f_loop() __wine_inc_seh_f_loop @ cdecl -norelay __wine_set_seh_f_loop(long) __wine_set_seh_f_loop @ cdecl -norelay __wine_push_seh_f_reraise(long) __wine_push_seh_f_reraise @ cdecl -norelay __wine_pop_seh_f_reraise() __wine_pop_seh_f_reraise diff -ur -x CVS -x 'bigdif*' -x autom4te.cache ../wine.test/dlls/ntdll/tests/seh_macros.c ./dlls/ntdll/tests/seh_macros.c --- ../wine.test/dlls/ntdll/tests/seh_macros.c 2003-01-13 19:29:54.000000000 -0600 +++ ./dlls/ntdll/tests/seh_macros.c 2003-01-13 19:37:15.000000000 -0600 @@ -29,6 +29,17 @@ { int x; + /* + * this macro should be quieter than assert(), although the finally() process still + * generates asserts, ATM. Once that is fixed the test should be silent. + */ + #define CRASH_OUT \ + \ + if (x) /* I think this branch stops gcc from performing optimizations that break some tests */ \ + x += (int)(*(int **)0); \ + else \ + x -= (int)(*(int **)0); + trace("beginning TryMacros:\n"); trace(" basic no-exception-handling macro test\n"); @@ -44,9 +55,9 @@ x = 0; __try { x++; - x = (int)(*(int **)0); - x++; /* never executed */ - } __except( ( (x==1) ? ( ok(FALSE, "x should be 1 was %d",x) ) : (x=3) ), 1) { + CRASH_OUT; + x++; + } __except( ( (x!=1) ? ( ok(FALSE, "x should be 1 was %d",x) ) : (x=3) ), 1) { ok((x==3), "x should be 3 was %d", x); if (x==3) x = 4; } @@ -64,7 +75,7 @@ } __except(0) { ok(FALSE, "exception handler code shouldn't run"); x = -99; - assert(FALSE); + CRASH_OUT; } ok((x==2), "x should be 2 was %d", x); if (x==2) x = 3; @@ -82,11 +93,11 @@ __try { ok((x==0), "x should be 0 was %d", x); if (x==0) x = 1; - assert(FALSE); + CRASH_OUT; } __except(1) { ok((x==1), "x should be 1 was %d", x); if (x==1) x = 2; - assert(FALSE); + CRASH_OUT; } ok(FALSE, "this code should be skipped"); } __except(1) { @@ -95,7 +106,7 @@ __try { ok ((x==3), "x should be 3 was %d", x); if (x==3) x = 4; - assert(FALSE); + CRASH_OUT; } __except(1) { ok ((x==4), "x should be 4 was %d", x); if (x==4) x = 5; @@ -128,13 +139,13 @@ trace(" absurdly nested exceptions test: some exceptions\n"); x = 0; - #define nesttry1(x) __try {x++; } __except(1) { x++; assert(FALSE); } - #define nesttry2(x) __try {x++; nesttry1(x) } __except(1) { x++; nesttry1(x); assert(FALSE); } - #define nesttry3(x) __try {x++; nesttry2(x) } __except(1) { x++; nesttry2(x); assert(FALSE); } - #define nesttry4(x) __try {x++; nesttry3(x) } __except(1) { x++; nesttry3(x); assert(FALSE); } - #define nesttry5(x) __try {x++; nesttry4(x) } __except(1) { x++; nesttry4(x); assert(FALSE); } - #define nesttry6(x) __try {x++; nesttry5(x) } __except(1) { x++; nesttry5(x); assert(FALSE); } - #define nesttry7(x) __try {x++; nesttry6(x); assert(FALSE); } __except(1) { x++; nesttry6(x); assert(FALSE); } + #define nesttry1(x) __try {x++; } __except(1) { x++; CRASH_OUT; } + #define nesttry2(x) __try {x++; nesttry1(x) } __except(1) { x++; nesttry1(x); CRASH_OUT; } + #define nesttry3(x) __try {x++; nesttry2(x) } __except(1) { x++; nesttry2(x); CRASH_OUT; } + #define nesttry4(x) __try {x++; nesttry3(x) } __except(1) { x++; nesttry3(x); CRASH_OUT; } + #define nesttry5(x) __try {x++; nesttry4(x) } __except(1) { x++; nesttry4(x); CRASH_OUT; } + #define nesttry6(x) __try {x++; nesttry5(x) } __except(1) { x++; nesttry5(x); CRASH_OUT; } + #define nesttry7(x) __try {x++; nesttry6(x); CRASH_OUT; } __except(1) { x++; nesttry6(x); CRASH_OUT; } __try { nesttry7(x) } __except (1) { @@ -174,7 +185,7 @@ __try { __try { x++; - assert(FALSE); + CRASH_OUT; x++; } __finally { ok((x==1), "x should be 1 was %d", x); @@ -215,7 +226,7 @@ __try { ok((x==2), "x should be 2 was %d", x); if (x==2) x = 3; - assert(FALSE); + CRASH_OUT; ok(FALSE, "this code should not execute"); } __finally { ok((x==3), "x should be 3 was %d", x); @@ -249,7 +260,7 @@ ok((x==3), "x should be 3 was %d", x); if (x==3) x = 4; } - assert(FALSE); + CRASH_OUT; ok(FALSE, "this code should not execute"); } __finally { ok((x==4), "x should be 4 was %d", x); @@ -262,7 +273,57 @@ } ok((x==6), "x should be 6 was %d", x); - + trace(" absurdly nested maze of try/finally clauses\n"); + + #define tryfinallymaze0(x) __try { x++; CRASH_OUT; } __finally { x++; } + #define tryfinallymaze1(x) __try { x++; tryfinallymaze0(x); } __except(1) { tryfinallymaze0(x); x++; } + #define tryfinallymaze2(x) __try { tryfinallymaze1(x); x++; } __finally { tryfinallymaze1(x); x++; CRASH_OUT; } + #define tryfinallymaze3(x) __try { tryfinallymaze2(x); x++; } __except(1) { tryfinallymaze2(x); } + #define tryfinallymaze4(x) __try { tryfinallymaze3(x); x++; } __finally { tryfinallymaze3(x); x++; CRASH_OUT; } + #define tryfinallymaze5(x) __try { tryfinallymaze4(x); x++; } __except(1) { tryfinallymaze4(x); } + #define tryfinallymaze6(x) __try { tryfinallymaze5(x); x++; } __finally { tryfinallymaze5(x); x++; CRASH_OUT; } + #define tryfinallymaze7(x) __try { tryfinallymaze6(x); x++; } __except(1) { x++; } + + x = 0; + + tryfinallymaze7(x) + + ok((x==161), "x should be 161 was %d", x); + + #undef tryfinallymaze7 + #undef tryfinallymaze6 + #undef tryfinallymaze5 + #undef tryfinallymaze4 + #undef tryfinallymaze3 + #undef tryfinallymaze2 + #undef tryfinallymaze1 + #undef tryfinallymaze0 + + trace(" test of the __leave macro in a __try/__except clause\n"); + + x = 0; + __try { + x = 1; + __leave; + x = 2; + } __except(1) { + x = 3; + } + ok((x==1), "x should be 1 was %d",x); + + trace(" test of the __leave macro in a __try/__finally clause\n"); + + x = 0; + __try { + x = 1; + __leave; + x = 2; + } __finally { + ok((x==1), "x should be 1 was %d",x); + if (x==1) x = 3; + } + ok((x==3), "x should be 3 was %d", x); + trace("End.\n"); } diff -ur -x CVS -x 'bigdif*' -x autom4te.cache ../wine.test/include/wine/exception.h ./include/wine/exception.h --- ../wine.test/include/wine/exception.h 2003-01-13 19:29:54.000000000 -0600 +++ ./include/wine/exception.h 2003-01-13 16:49:56.000000000 -0600 @@ -160,20 +160,26 @@ /* these functions simultate a global thread-local variable */ extern int __wine_get_seh_f_loop(); extern void __wine_set_seh_f_loop(int); +extern void __wine_inc_seh_f_loop(); /* these functions implement a TLS stack of elements (currently int's). */ /* FIXME: push/pop an exception info struct instead of an int */ extern int __wine_pop_seh_f_reraise(); extern void __wine_push_seh_f_reraise(int); +#ifndef __NO_VC_SEH_MACROS__ + #define __try \ \ if ( ({ \ + __label__ __leavelabel; \ int seh_result = -2; \ static WINE_EXCEPTION_FILTER(seh_handler); \ __TRY { #define __finally \ - \ + \ + __leavelabel: \ + if (0) { goto __leavelabel; } /* appease compiler */ \ } __EXCEPT(seh_handler) { \ } __ENDTRY \ WINE_EXCEPTION_FILTER(seh_handler) { \ @@ -184,8 +190,7 @@ } \ if (seh_result != -4) __wine_push_seh_f_reraise(0); \ 0; }) ) { } else \ - /* FIXME: this could be done more efficiently */ \ - for (__wine_set_seh_f_loop(0); __wine_get_seh_f_loop() <= 1; __wine_set_seh_f_loop(__wine_get_seh_f_loop() + 1)) \ + for (__wine_set_seh_f_loop(0); __wine_get_seh_f_loop() <= 1; __wine_inc_seh_f_loop() ) \ if (__wine_get_seh_f_loop() == 1) { \ if (__wine_pop_seh_f_reraise()) { \ /* FIXME: re-raise from stored exception info */ assert(FALSE); \ @@ -195,7 +200,9 @@ } else #define __except(...) \ - \ + \ + __leavelabel: \ + if (0) { goto __leavelabel; } /* appease compiler */ \ } __EXCEPT(seh_handler) { \ seh_result = -3; \ } __ENDTRY \ @@ -205,8 +212,11 @@ } \ (seh_result != -3); }) ) { } else -/* FIXME */ -#define __leave assert(FALSE) +#define __leave \ + \ + goto __leavelabel + +#endif /* NO_VC_SEH_MACROS */ #endif /* USE_COMPILER_EXCEPTIONS */ -- gmt p.s., note: the newline between the #endif and the "--\ngmt" is part of the .diff. "If everyone is thinking alike then somebody isn't thinking." --George S. Patton