Without it, __wine_rtl_unwind confuses the unwinding code on x64 and it then triggers an infinite exception loop.
This can be reproduced for example in msctf inputprocessor's test, with the test_MultiThreadApartment test case that raises an E_NOINTERFACE exception. It fails to unwind correctly on x64 with WINEDEBUG=-all,+seh. ---
I don't understand very well what is going on here, the issue looks to be a misaligned stack somewhere that leads to invalid rsp/rbp when unwinded. It happens when __widl_exception_handler calls __wine_rtl_unwind to unwind the stack to the RpcFinally/RpcExcept statements, for example when an RPC error is raised (in this case, when E_NOINTERFACE is raised because of impossible marshalling).
These .seh_* statements are generated on cross-compiled C functions, and adding them for assembly functions seems to solve the issue.
dlls/winecrt0/exception.c | 1 + include/wine/asm.h | 14 ++++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/dlls/winecrt0/exception.c b/dlls/winecrt0/exception.c index df7315e6d40..66c7efbb0e0 100644 --- a/dlls/winecrt0/exception.c +++ b/dlls/winecrt0/exception.c @@ -122,6 +122,7 @@ __ASM_GLOBAL_FUNC( __wine_rtl_unwind, "movq %rsp,%rbp\n\t" __ASM_CFI(".cfi_def_cfa_register %rbp\n\t") "subq $0x20,%rsp\n\t" + __ASM_SEH(".seh_stackalloc 0x20\n\t") "movq %r8,%r9\n\t" /* retval = final target */ "movq %rdx,%r8\n\t" /* record */ "leaq __wine_unwind_trampoline(%rip),%rdx\n\t" /* target = trampoline */ diff --git a/include/wine/asm.h b/include/wine/asm.h index c1a6819cd52..691a8aeb98b 100644 --- a/include/wine/asm.h +++ b/include/wine/asm.h @@ -49,14 +49,20 @@ # define __ASM_FUNC_TYPE(name) ".type " name ",@function" #endif
+#if defined(_WIN64) && defined(__MINGW32__) +#define __ASM_SEH(code) code +#else +#define __ASM_SEH(code) "" +#endif + #ifdef __GNUC__ # define __ASM_DEFINE_FUNC(name,code) \ - asm(".text\n\t.align 4\n\t.globl " name "\n\t" __ASM_FUNC_TYPE(name) "\n" name ":\n\t" \ - __ASM_CFI(".cfi_startproc\n\t") code __ASM_CFI("\n\t.cfi_endproc") ); + asm(".text\n\t.align 4\n\t.globl " name "\n\t" __ASM_FUNC_TYPE(name) __ASM_SEH("\n\t.seh_proc " name) "\n" name ":\n\t" \ + __ASM_CFI(".cfi_startproc\n\t") code __ASM_CFI("\n\t.cfi_endproc") __ASM_SEH("\n\t.seh_endproc") ); #else # define __ASM_DEFINE_FUNC(name,code) void __asm_dummy_##__LINE__(void) { \ - asm(".text\n\t.align 4\n\t.globl " name "\n\t" __ASM_FUNC_TYPE(name) "\n" name ":\n\t" \ - __ASM_CFI(".cfi_startproc\n\t") code __ASM_CFI("\n\t.cfi_endproc") ); } + asm(".text\n\t.align 4\n\t.globl " name "\n\t" __ASM_FUNC_TYPE(name) __ASM_SEH("\n\t.seh_proc " name) "\n" name ":\n\t" \ + __ASM_CFI(".cfi_startproc\n\t") code __ASM_CFI("\n\t.cfi_endproc") __ASM_SEH("\n\t.seh_endproc") ); } #endif
#define __ASM_GLOBAL_FUNC(name,code) __ASM_DEFINE_FUNC(__ASM_NAME(#name),code) -- 2.23.0.rc1