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;
} SEH_TLS_TEMP;

SEH_TLS_TEMP SEH_TLS_TEMPS;

WINE_EXCEPTION_HANDLER_FUNC WineSEHHandler(args) {
  if (setjmp(SEH_TLS_TEMPS.jmp)) {
    switch(SEH_TLS_TEMPS.exception_code) 
    ...   /* 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(...); \
                 __wine_pop_frame();
                 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 
struct.

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().

Now:

(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

gmt





More information about the wine-devel mailing list