diff options
author | Kevin B Kenny <kennykb@acm.org> | 2005-06-23 19:48:26 (GMT) |
---|---|---|
committer | Kevin B Kenny <kennykb@acm.org> | 2005-06-23 19:48:26 (GMT) |
commit | ca2c58dc87aed527aea5e80d39a72c95e537f41c (patch) | |
tree | db1f99db3864102b1310d348031588f60b424620 /win/tclWinChan.c | |
parent | 10e79f4f5579a69921d990800c1ead43c1486443 (diff) | |
download | tcl-ca2c58dc87aed527aea5e80d39a72c95e537f41c.zip tcl-ca2c58dc87aed527aea5e80d39a72c95e537f41c.tar.gz tcl-ca2c58dc87aed527aea5e80d39a72c95e537f41c.tar.bz2 |
bug 1225957
Diffstat (limited to 'win/tclWinChan.c')
-rw-r--r-- | win/tclWinChan.c | 202 |
1 files changed, 97 insertions, 105 deletions
diff --git a/win/tclWinChan.c b/win/tclWinChan.c index c4ec930..db8b75b 100644 --- a/win/tclWinChan.c +++ b/win/tclWinChan.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclWinChan.c,v 1.42 2005/06/08 14:12:19 dkf Exp $ + * RCS: @(#) $Id: tclWinChan.c,v 1.43 2005/06/23 19:48:50 kennykb Exp $ */ #include "tclWinInt.h" @@ -127,16 +127,24 @@ static Tcl_ChannelType fileChannelType = { FileTruncateProc, /* Truncate proc. */ }; -#if defined(HAVE_NO_SEH) && defined(TCL_MEM_DEBUG) -static void *INITIAL_ESP, *INITIAL_EBP, *INITIAL_HANDLER; -static void *RESTORED_ESP, *RESTORED_EBP, *RESTORED_HANDLER; -#endif /* HAVE_NO_SEH && TCL_MEM_DEBUG */ - #ifdef HAVE_NO_SEH -static __attribute__ ((cdecl)) EXCEPTION_DISPOSITION -_except_makefilechannel_handler(struct _EXCEPTION_RECORD *ExceptionRecord, - void *EstablisherFrame, struct _CONTEXT *ContextRecord, - void *DispatcherContext); + +/* + * Unlike Borland and Microsoft, we don't register exception handlers + * by pushing registration records onto the runtime stack. Instead, we + * register them by creating an EXCEPTION_REGISTRATION within the activation + * record. + */ + +typedef struct EXCEPTION_REGISTRATION { + struct EXCEPTION_REGISTRATION* link; + EXCEPTION_DISPOSITION (*handler)( struct _EXCEPTION_RECORD*, void*, + struct _CONTEXT*, void* ); + void* ebp; + void* esp; + int status; +} EXCEPTION_REGISTRATION; + #endif /* @@ -1049,6 +1057,9 @@ Tcl_MakeFileChannel(rawHandle, mode) * and TCL_WRITABLE to indicate file * mode. */ { +#ifdef HAVE_NO_SEH + EXCEPTION_REGISTRATION registration; +#endif char channelName[16 + TCL_INTEGER_SPACE]; Tcl_Channel channel = NULL; HANDLE handle = (HANDLE) rawHandle; @@ -1137,81 +1148,93 @@ Tcl_MakeFileChannel(rawHandle, mode) * of this duped handle which might throw EXCEPTION_INVALID_HANDLE. */ -#ifdef HAVE_NO_SEH -# ifdef TCL_MEM_DEBUG - __asm__ __volatile__ ( - "movl %%esp, %0" "\n\t" - "movl %%ebp, %1" "\n\t" - "movl %%fs:0, %2" "\n\t" - : "=m"(INITIAL_ESP), - "=m"(INITIAL_EBP), - "=r"(INITIAL_HANDLER) ); -# endif /* TCL_MEM_DEBUG */ - - __asm__ __volatile__ ( - "pushl %%ebp" "\n\t" - "pushl %0" "\n\t" - "pushl %%fs:0" "\n\t" - "movl %%esp, %%fs:0" - : - : "r" (_except_makefilechannel_handler) ); - result = CloseHandle(dupedHandle); - __asm__ __volatile__ ( - "jmp makefilechannel_pop" "\n" - "makefilechannel_reentry:" "\n\t" - "movl %%fs:0, %%eax" "\n\t" - "movl 0x8(%%eax), %%esp" "\n\t" - "movl 0x8(%%esp), %%ebp" "\n" - "movl $0, %0" "\n" - "makefilechannel_pop:" "\n\t" - "movl (%%esp), %%eax" "\n\t" - "movl %%eax, %%fs:0" "\n\t" - "add $12, %%esp" "\n\t" - : "=m"(result) - : - : "%eax"); - -# ifdef TCL_MEM_DEBUG + result = 0; +#ifndef HAVE_NO_SEH + __try { + CloseHandle(dupedHandle); + result = 1; + } __except (EXCEPTION_EXECUTE_HANDLER) {} +#else + /* + * Don't have SEH available, do things the hard way. + * Note that this needs to be one block of asm, to avoid stack + * imbalance; also, it is illegal for one asm block to contain + * a jump to another. + */ + __asm__ __volatile__ ( - "movl %%esp, %0" "\n\t" - "movl %%ebp, %1" "\n\t" - "movl %%fs:0, %2" "\n\t" - : "=m"(RESTORED_ESP), - "=m"(RESTORED_EBP), - "=r"(RESTORED_HANDLER) ); - - if (INITIAL_ESP != RESTORED_ESP) { - Tcl_Panic("ESP restored incorrectly"); - } - if (INITIAL_EBP != RESTORED_EBP) { - Tcl_Panic("EBP restored incorrectly"); - } - if (INITIAL_HANDLER != RESTORED_HANDLER) { - Tcl_Panic("HANDLER restored incorrectly"); - } -# endif /* TCL_MEM_DEBUG */ - if (result == 0) { /* - * The handle failed to close. The original is therefore - * invalid. + * Pick up parameters before messing with the stack */ - return NULL; - } + "movl %[dupedHandle], %%ebx" "\n\t" -#else - __try { - result = CloseHandle(dupedHandle); - } __except (EXCEPTION_EXECUTE_HANDLER) { /* - * Definately an invalid handle. So, therefore, the original - * is invalid also. + * Construct an EXCEPTION_REGISTRATION to protect the + * call to CloseHandle */ + "leal %[registration], %%edx" "\n\t" + "movl %%fs:0, %%eax" "\n\t" + "movl %%eax, 0x0(%%edx)" "\n\t" /* link */ + "leal 1f, %%eax" "\n\t" + "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */ + "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */ + "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */ + "movl $0, 0x10(%%edx)" "\n\t" /* status */ + + /* Link the EXCEPTION_REGISTRATION on the chain */ + + "movl %%edx, %%fs:0" "\n\t" + + /* Call CloseHandle( dupedHandle ) */ + + "pushl %%ebx" "\n\t" + "call _CloseHandle@4" "\n\t" + + /* + * Come here on normal exit. Recover the EXCEPTION_REGISTRATION + * and put a TRUE status return into it. + */ + + "movl %%fs:0, %%edx" "\n\t" + "movl $1, %%eax" "\n\t" + "movl %%eax, 0x10(%%edx)" "\n\t" + "jmp 2f" "\n" + + /* + * Come here on an exception. Recover the EXCEPTION_REGISTRATION + */ + + "1:" "\t" + "movl %%fs:0, %%edx" "\n\t" + "movl 0x8(%%edx), %%edx" "\n\t" + + /* + * Come here however we exited. Restore context from the + * EXCEPTION_REGISTRATION in case the stack is unbalanced. + */ + + "2:" "\t" + "movl 0xc(%%edx), %%esp" "\n\t" + "movl 0x8(%%edx), %%ebp" "\n\t" + "movl 0x0(%%edx), %%eax" "\n\t" + "movl %%eax, %%fs:0" "\n\t" + + : + /* No outputs */ + : + [registration] "m" (registration), + [dupedHandle] "m" (dupedHandle) + : + "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory" + ); + result = registration.status; +#endif + if (result == FALSE) { return NULL; } -#endif /* HAVE_NO_SEH */ /* Fall through, the handle is valid. */ @@ -1229,37 +1252,6 @@ Tcl_MakeFileChannel(rawHandle, mode) /* *---------------------------------------------------------------------- * - * _except_makefilechannel_handler -- - * - * SEH exception handler for Tcl_MakeFileChannel. - * - * Results: - * See Tcl_MakeFileChannel. - * - * Side effects: - * See Tcl_MakeFileChannel. - * - *---------------------------------------------------------------------- - */ -#ifdef HAVE_NO_SEH -static -__attribute__ ((cdecl)) -EXCEPTION_DISPOSITION -_except_makefilechannel_handler( - struct _EXCEPTION_RECORD *ExceptionRecord, - void *EstablisherFrame, - struct _CONTEXT *ContextRecord, - void *DispatcherContext) -{ - __asm__ __volatile__ ( - "jmp makefilechannel_reentry"); - return 0; /* Function does not return */ -} -#endif - -/* - *---------------------------------------------------------------------- - * * TclpGetDefaultStdChannel -- * * Constructs a channel for the specified standard OS handle. |