Whenever an app switches stack using its own code, we are left with stale frame handlers (which, on x64, is Wine workaround for missing compiler support for SEH handling). This is one of the two most common places breaking the apps as here frame handler is created for every thread and stays there (unlike most of other __TRY usages which are narrow scoped to Wine code without calling apps code callbacks). The only other place nearly as common is exception unwinding (where frame handlers are left whenever an app sets context on its own without calling RtlRestoreContext, like .Net core does). So I hope for these two cases having manual wrappers with proper .seh handling is justified.
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/thread.c | 36 +++++++++++++++++++++++++++++++++++- include/wine/asm.h | 1 + 2 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 01733585a75..82a470271d9 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -285,7 +285,41 @@ void DECLSPEC_HIDDEN call_thread_func( PRTL_THREAD_START_ROUTINE entry, void *ar __ENDTRY }
-#else /* __i386__ */ +#elif /* __i386__ */ defined(__x86_64__) && defined(__ASM_SEH_SUPPORTED) +EXCEPTION_DISPOSITION WINAPI call_thread_func_handler( EXCEPTION_RECORD *rec, ULONG64 frame, + CONTEXT *context, DISPATCHER_CONTEXT *dispatch ) +{ + EXCEPTION_POINTERS ep = { rec, context }; + + WARN( "Unhandled exception, calling filter.\n" ); + + switch (call_unhandled_exception_filter( &ep )) + { + case EXCEPTION_CONTINUE_SEARCH: + return ExceptionContinueSearch; + case EXCEPTION_CONTINUE_EXECUTION: + return ExceptionContinueExecution; + case EXCEPTION_EXECUTE_HANDLER: + break; + } + NtTerminateProcess( GetCurrentProcess(), rec->ExceptionCode ); + return ExceptionContinueExecution; +} + +extern void WINAPI RtlUserThreadStart( PRTL_THREAD_START_ROUTINE entry, void *arg ); +__ASM_GLOBAL_FUNC( RtlUserThreadStart, + "subq $0x28,%rsp\n\t" + ".seh_stackalloc 0x28\n\t" + ".seh_endprologue\n\t" + "movq %rdx,%r8\n\t" + "movq %rcx,%rdx\n\t" + "xorq %rcx,%rcx\n\t" + "movq " __ASM_NAME( "pBaseThreadInitThunk" ) "(%rip),%r9\n\t" + "call *%r9\n\t" + "int3\n\t" + ".seh_handler call_thread_func_handler, @except\n\t" ) + +#else /* defined(__x86_64__) && defined(__ASM_SEH_SUPPORTED) */
void WINAPI RtlUserThreadStart( PRTL_THREAD_START_ROUTINE entry, void *arg ) { diff --git a/include/wine/asm.h b/include/wine/asm.h index a158449d6a5..2a21bceb55e 100644 --- a/include/wine/asm.h +++ b/include/wine/asm.h @@ -54,6 +54,7 @@ # define __ASM_SEH(str) # else # define __ASM_SEH(str) str +# define __ASM_SEH_SUPPORTED # endif #else # define __ASM_SEH(str)
Since the whole added part is guarded with __ASM_SEH_SUPPORTED, I omitted __ASM_SEH macro in the asm code.