rpc exception

Gregory M. Turner gmturner007 at ameritech.net
Thu May 1 00:26:16 CDT 2003

On Monday 21 April 2003 10:55 pm, Alexandre Julliard wrote:
> "Dimitrie O. Paun" <dpaun at rogers.com> writes:
> > Just like with threads, why not cross that bridge when we get there?
> > Is it really worth it to penalize 99% of the people? When we port to
> > another compiler, it will be a lot simpler to worry about those pieces
> > of code, rather than have no code at all.
> The difference with threads is that we know all platforms have some
> kind of threading, so we know that we can adapt the code when
> needed. I don't think any other C compiler supports local functions
> (even g++ doesn't AFAIK), so there won't be much hope of ever making
> it work. Of course we could decide to stop supporting other compilers,
> but I don't think everybody would be happy with that.
> > Also, not accepting code into Wine that depend on exception is one thing,
> > but what about Winelib? We can have the exception code commented out if
> > __WINESRC__ is defined, but at least lets get it in if it works, it will
> > plug a big Winelib hole.
> Sure, we can make the macros available for Winelib.

OK, folks, I think I may have a plan to create a portable __except, please let 
me know your thoughts, as there are many places I might be going wrong.  What 
follows is a totally new approach compared to my old attempts; I haven't 
tried to implement a similar implementation "plan" for __finally yet.

Allright, here goes, in crap / gibberish ("pseudocode") form:

/* GLOBAL structure instance somewhere (ntdll?)  Thread-local */
typedef struct { 
  bool do_handler_bit;
  DWORD exception_code;
  jmp_buf jmp;


  if (setjmp(SEH_TLS_TEMPS.jmp)) {
    ...   /* the rest is like __wine_exception_handler in
             ntdll/exception.c */
  } else {
    do_handler_bit = 0;
    longjmp(exception_record_argument->jmpbuf, 0);

/* now here are the parts that would be in include/wine/exception.h */

/* exactly the same as __TRY, really just #define __try __TRY */
#define __try \
    do { __WINE_FRAME __f; \
         int __first = 1; \
         for (;;) if (!__first) \
         { \
             do {

#define __except(expr) \
             } while(0); \
             SEH_TLS_TEMPS.do_handler_bit = 0;
             __wine_pop_frame( &__f.frame ); \
             break; \
         } else { \
             __f.frame.Handler = (PEXCEPTION_HANDLER) WineSEHHandler; \
             __f.u.filter = NULL; \
             __wine_push_frame( &__f.frame ); \
             if (setjmp( __f.jmp)) { \
                 int ecode; \
                 const __WINE_FRAME * const __eptr WINE_UNUSED = &__f; \
                 /* exception code hacks go here... */ \
                 if ((ecode = (expr)) != EXECUTE_HANDLER)  { \
                     SEH_TLS_TEMPS.exception_code = ecode \
		     longjmp(SEH_TLS_TEMPS.jmp, 0); \
                 } \
		 RtlUnwind(...); \
                 SEH_TLS_TEMPS.do_handler_bit = 1; \
                 break; \
             } \
             __first = 0; \
         } \
    } while (0); \
    if (SEH_TLS_TEMPS.do_handler_bit)

This obviously is leaving some stuff out.  For example, this wouldn't work 
with nested exceptions.  However, that seems possible to fix, if not by 
abusing the jmp_buf right in the frame structure then by creating a stack of 
SEH_TLS_TEMP structures instead of just a single instance, or maybe in some 
other clever way like attaching the SEH_TLS_TEMP struct to the wine frame 

What I'm more concerned about is the following:

A() runs setjmp, calls B(), which calls C(), which calls D().  A() would be 
the user's function (whatever it is) and D() would be WineSEHHandler above. 
D() runs setjmp again on a second jump buffer, and calls longjmp to do a 
nonlocal goto into A().


(a) if the exception code runs, A() keeps running and eventually just 
returns... will it properly release all the stack from B(), C() and so on or 
is this a problem?  I guess its OK since the SP just goes back to what it was 
when I called setjmp, right?

(b) if the exception code doesn't run, A() runs longjmp again, to non-local 
goto /back/ into D(), using the second jmp_buf.  This returns normally and 
would, I guess, expect to unwind the stack normally through C(), B() and so 
on... (this is all ignoring the fact that flow-of-control was interrupted by 
an exception, but for my purposes I don't think it matters).

Are either of these scenarios illegal (in wine)?  If not, I think I can make 
it work.  Another concern would be that two longjmps are just too slow to be 
used, but since that only occurs in an exception scenario I think it's OK...

Thoughts, flames, etc?

"Security is mostly superstition. It does not exist in nature,
nor do the children of men as a whole experience it. Avoiding
danger is no safer in the long run than outright exposure. Life is
either a daring adventure, or nothing. To keep our faces toward
change and behave like free spirits in the presence of fate is
strength undefeatable." --Helen Keller


More information about the wine-devel mailing list