Index: stacklesseval.c =================================================================== --- stacklesseval.c (revision 88940) +++ stacklesseval.c (working copy) @@ -84,7 +84,89 @@ } } +#ifdef _SEH32 +/// added by gil colgate + struct EXCEPTION_REGISTRATION +{ + struct EXCEPTION_REGISTRATION* prev; // we start at the head, and go prev to go up the stack to the top. Ends in 0xfffffffff + FARPROC handler; +}; +#define EXCEPTION_END ((struct EXCEPTION_REGISTRATION *)0xFFFFFFFF) +#define EXCEPTION_SAVED(x) ((struct EXCEPTION_REGISTRATION *)(x) != EXCEPTION_END) + +/// added by gil colgate +#if DEBUG_SEH32 +void slp_debug_check_exeption_list(struct EXCEPTION_REGISTRATION *pVCExcRec) +{ + // will crash if exception list is bad, usually. This is the intention... + // it's how the debug works. It will crash immediately if exception list is wrong rather than later. + // Walk the linked list of frames. 0xFFFFFFFF indicates the end of list + while ( EXCEPTION_END != pVCExcRec ) + { + pVCExcRec = (pVCExcRec->prev); + } +} +#endif + +/// added by gil colgate. In the normal case our program never calls this, I had to abuse our module +/// files to get it to happen. +void slp_patch_exception_list(struct EXCEPTION_REGISTRATION *pListToPatch, struct EXCEPTION_REGISTRATION *patchPoint, DWORD stackPtrTop ) +{ + if( pListToPatch == EXCEPTION_END) // I don't think this can happen + return; + if((DWORD)pListToPatch > stackPtrTop) // should not happen + return; + + // Walk the linked list of frames. 0xFFFFFFFF indicates the end pListToPatchPrev list + while ( (DWORD)pListToPatch->prev < stackPtrTop) + { + pListToPatch = (pListToPatch->prev); + } + + pListToPatch->prev = patchPoint; +} + + +/// added by gil colgate. In the normal case our program never calls this, I had to abuse our module +/// files to get it to happen. +struct EXCEPTION_REGISTRATION *slp_get_exception_list_in_stack_above(struct EXCEPTION_REGISTRATION *pListToCheck, DWORD stackPtrTop ) +{ + // find the spot where we can reattach the list, not making any assumptions about the stack above us. + if(pListToCheck == EXCEPTION_END) + return EXCEPTION_END; + + // Walk the linked list of frames. 0xFFFFFFFF (EXCEPTION_END) indicates the end pListToPatchPrev list + while ( (DWORD)(pListToCheck) < stackPtrTop) + { + pListToCheck = pListToCheck->prev; + } + + return pListToCheck; +} + +// This is key to fixing the issue. Added by gil colgate +DWORD slp_exception_to_save(intptr_t *stack) +{ + // save the exception list if we need to. + // We only need to if the stack area we are saving out + // contains an exception list. If the exception stack points + // higher up the stack into the code above the python calls + // we do not need to. + + intptr_t *curExceptionList = (intptr_t *) __readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); + + if(curExceptionList < stack) + { + return (DWORD)curExceptionList; // item we need to save + } + else + { + return (DWORD)EXCEPTION_END; // no need to save, mark with -1 + } +} +#endif + PyCStackObject * slp_cstack_new(PyCStackObject **cst, intptr_t *stackref, PyTaskletObject *task) { @@ -118,8 +200,11 @@ (*cst)->nesting_level = ts->st.nesting_level; #ifdef _SEH32 //save the SEH handler - (*cst)->exception_list = (DWORD) - __readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); + #if DEBUG_SEH32 + slp_debug_check_exeption_list((struct EXCEPTION_REGISTRATION *)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList))); + #endif + (*cst)->exception_list = slp_exception_to_save((*cst)->startaddr); + #endif return *cst; } @@ -132,9 +217,11 @@ memcpy((cstprev)->stack, (cstprev)->startaddr - Py_SIZE(cstprev), stsizeb); #ifdef _SEH32 + #if DEBUG_SEH32 + slp_debug_check_exeption_list((struct EXCEPTION_REGISTRATION *)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList))); + #endif + (cstprev)->exception_list = slp_exception_to_save((cstprev)->startaddr); //save the SEH handler - cstprev->exception_list = (DWORD) - __readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); #endif return stsizeb; } @@ -145,14 +232,42 @@ #endif slp_cstack_restore(PyCStackObject *cst) { + +#ifdef _SEH32 + struct EXCEPTION_REGISTRATION *exList; + struct EXCEPTION_REGISTRATION * oldListStart; + if(EXCEPTION_SAVED( cst->exception_list)) + oldListStart = slp_get_exception_list_in_stack_above((struct EXCEPTION_REGISTRATION * )__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)), (DWORD)cst->startaddr ); + else if(slp_exception_to_save(cst->startaddr) != (DWORD)EXCEPTION_END) + { + // patch the old list if the new list is empty, and we have an old list. + oldListStart = slp_get_exception_list_in_stack_above((struct EXCEPTION_REGISTRATION * )__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)), (DWORD)cst->startaddr ); + __writefsdword(FIELD_OFFSET(NT_TIB, ExceptionList), (DWORD)oldListStart); + + #if DEBUG_SEH32 + slp_debug_check_exeption_list((struct EXCEPTION_REGISTRATION *)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList))); + #endif + } +#endif + cst->tstate->st.nesting_level = cst->nesting_level; /* mark task as no longer responsible for cstack instance */ cst->task = NULL; memcpy(cst->startaddr - Py_SIZE(cst), &cst->stack, Py_SIZE(cst) * sizeof(intptr_t)); #ifdef _SEH32 - //restore the SEH handler - __writefsdword(FIELD_OFFSET(NT_TIB, ExceptionList), (DWORD)(cst->exception_list)); + //restore the SEH handler, if it was changed + if(EXCEPTION_SAVED(cst->exception_list)) + { + __writefsdword(FIELD_OFFSET(NT_TIB, ExceptionList), (DWORD)(cst->exception_list)); + exList = (struct EXCEPTION_REGISTRATION *)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); + slp_patch_exception_list(exList, oldListStart, (DWORD)cst->startaddr ); + } + + #if DEBUG_SEH32 + slp_debug_check_exeption_list((struct EXCEPTION_REGISTRATION *)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList))); + #endif + #pragma warning(default:4733) #endif }