diff --git a/src/core/thread.d b/src/core/thread.d index 147725d0c5..a4e421bd3f 100644 --- a/src/core/thread.d +++ b/src/core/thread.d @@ -3908,6 +3908,10 @@ version( LDC ) version( X86 ) version = CheckFiberMigration; version( X86_64 ) version = CheckFiberMigration; } + else version( Windows ) + { + version( X86 ) version = CheckFiberMigration; + } } // Fiber support for SjLj style exceptions @@ -4854,16 +4858,21 @@ private: finalHandler = reg.handler; } - pstack -= EXCEPTION_REGISTRATION.sizeof; + // With safeseh(?), the chain must not extend to the very top + // of the stack, otherwise the exception chain is also considered + // invalid. Reserving additional 4 bytes at the top of the stack will + // keep the EXCEPTION_REGISTRATION below that limit + size_t reserve = EXCEPTION_REGISTRATION.sizeof + 4; + pstack -= reserve; *(cast(EXCEPTION_REGISTRATION*)pstack) = EXCEPTION_REGISTRATION( sehChainEnd, finalHandler ); push( cast(size_t) &fiber_entryPoint ); // EIP - push( cast(size_t) m_ctxt.bstack - EXCEPTION_REGISTRATION.sizeof ); // EBP + push( cast(size_t) m_ctxt.bstack - reserve ); // EBP push( 0x00000000 ); // EDI push( 0x00000000 ); // ESI push( 0x00000000 ); // EBX - push( cast(size_t) m_ctxt.bstack - EXCEPTION_REGISTRATION.sizeof ); // FS:[0] + push( cast(size_t) m_ctxt.bstack - reserve ); // FS:[0] push( cast(size_t) m_ctxt.bstack ); // FS:[4] push( cast(size_t) m_ctxt.bstack - m_size ); // FS:[8] push( 0x00000000 ); // EAX diff --git a/src/ldc/eh/common.d b/src/ldc/eh/common.d index bbc0e5cc87..cd6f9fb146 100644 --- a/src/ldc/eh/common.d +++ b/src/ldc/eh/common.d @@ -36,6 +36,9 @@ extern(C) void fatalerror(in char* format, ...) abort(); } +version(Win32) {} else version = notMSVC; +version(notMSVC): + // ------------------------ // Reading DWARF data // ------------------------ diff --git a/src/ldc/eh/win32.d b/src/ldc/eh/win32.d index ab219e8538..a560dbc34b 100644 --- a/src/ldc/eh/win32.d +++ b/src/ldc/eh/win32.d @@ -278,7 +278,14 @@ nothrow: @property size_t length() const { return _length; } @property bool empty() const { return !length; } - + + void swap(ref ExceptionStack other) + { + auto olength = other._length; other._length = _length; _length = olength; + auto op = other._p; other._p = _p; _p = op; + auto ocap = other._cap; other._cap = _cap; _cap = ocap; + } + private: void grow() { @@ -458,7 +465,66 @@ int doRtlUnwind(void* pFrame, ExceptionRecord* eRecord, typeof(RtlUnwind)* handl ret; } } + +/////////////////////////////////////////////////////////////// +struct FiberContext +{ + ExceptionStack exceptionStack; + void* currentException; + void* currentExceptionContext; + int processingContext; +} + +FiberContext* fiberContext; + +extern(C) void** __current_exception() nothrow; +extern(C) void** __current_exception_context() nothrow; +extern(C) int* __processing_throw() nothrow; + +extern(C) void* _d_eh_swapContext(FiberContext* newContext) nothrow +{ + import rt.util.container.common : xmalloc; + import core.stdc.string : memset; + if (!fiberContext) + { + fiberContext = cast(FiberContext*) xmalloc(FiberContext.sizeof); + memset(fiberContext, 0, FiberContext.sizeof); + } + fiberContext.exceptionStack.swap(exceptionStack); + fiberContext.currentException = *__current_exception(); + fiberContext.currentExceptionContext = *__current_exception_context(); + fiberContext.processingContext = *__processing_throw(); + + if (newContext) + { + exceptionStack.swap(newContext.exceptionStack); + *__current_exception() = newContext.currentException; + *__current_exception_context() = newContext.currentExceptionContext; + *__processing_throw() = newContext.processingContext; + } + else + { + exceptionStack = ExceptionStack(); + *__current_exception() = null; + *__current_exception_context() = null; + *__processing_throw() = 0; + } + + FiberContext* old = fiberContext; + fiberContext = newContext; + return old; +} +static ~this() +{ + import core.stdc.stdlib : free; + if (fiberContext) + { + destroy(*fiberContext); + free(fiberContext); + } +} + /////////////////////////////////////////////////////////////// void msvc_eh_init() {