diff --git a/dll/win32/ucrtbase/ucrtbase.spec b/dll/win32/ucrtbase/ucrtbase.spec index e2ed7928125..4e5a6f355fc 100644 --- a/dll/win32/ucrtbase/ucrtbase.spec +++ b/dll/win32/ucrtbase/ucrtbase.spec @@ -126,6 +126,7 @@ @ cdecl __initialize_lconv_for_unsigned_char() @ cdecl -stub __intrinsic_abnormal_termination() # CHECKME @ cdecl -stub -norelay __intrinsic_setjmp(ptr) # _setjmp +@ cdecl -impsym _setjmp(long ptr) __intrinsic_setjmp @ cdecl -stub -arch=!i386 -norelay __intrinsic_setjmpex(ptr ptr) # _setjmpex @ cdecl __isascii(long) @ cdecl __iscsym(long) diff --git a/modules/rostests/apitests/crt/amd64/setjmp_helper.s b/modules/rostests/apitests/crt/amd64/setjmp_helper.s new file mode 100644 index 00000000000..05b3a235287 --- /dev/null +++ b/modules/rostests/apitests/crt/amd64/setjmp_helper.s @@ -0,0 +1,143 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: Test helper for x64 setjmp + * COPYRIGHT: Copyright 2025 Timo Kreuzer + */ + +#include +#include + +#ifdef TEST_UCRTBASE +#define _setjmp __intrinsic_setjmp +#define _setjmpex __intrinsic_setjmpex +#endif + +.const + +.align 16 +xmm6_data: + .quad HEX(0606060606060606), HEX(1616161616161616) +xmm7_data: + .quad HEX(0707070707070707), HEX(1717171717171717) +xmm8_data: + .quad HEX(0808080808080808), HEX(1818181818181818) +xmm9_data: + .quad HEX(0909090909090909), HEX(1919191919191919) +xmm10_data: + .quad HEX(0A0A0A0A0A0A0A0A), HEX(1A1A1A1A1A1A1A1A) +xmm11_data: + .quad HEX(0B0B0B0B0B0B0B0B), HEX(1B1B1B1B1B1B1B1B) +xmm12_data: + .quad HEX(0C0C0C0C0C0C0C0C), HEX(1C1C1C1C1C1C1C1C) +xmm13_data: + .quad HEX(0D0D0D0D0D0D0D0D), HEX(1D1D1D1D1D1D1D1D) +xmm14_data: + .quad HEX(0E0E0E0E0E0E0E0E), HEX(1E1E1E1E1E1E1E1E) +xmm15_data: + .quad HEX(0F0F0F0F0F0F0F0F), HEX(1F1F1F1F1F1F1F1F) + + +.code64 + +PUBLIC get_sp +get_sp: + lea rax, [rsp + 8] + ret + + +EXTERN _setjmp:PROC +EXTERN _setjmpex:PROC +PUBLIC setjmp_return_address + +PUBLIC call_setjmp +call_setjmp: + lea r10, _setjmp[rip] + jmp call_setjmp_common + +PUBLIC call_setjmpex +call_setjmpex: + lea r10, _setjmpex[rip] + jmp call_setjmp_common + +.PROC call_setjmp_common + + // Allocate space for non-volatile (normal+xmm) registers on the stack + sub rsp, 8 * 8 + 10 * 16 + 8 // +8 to align the stack to 16 bytes + + // Save non-volatile registers + mov [rsp + 0 * 8], rbx + mov [rsp + 1 * 8], rbp + mov [rsp + 2 * 8], rsi + mov [rsp + 3 * 8], rdi + mov [rsp + 4 * 8], r12 + mov [rsp + 5 * 8], r13 + mov [rsp + 6 * 8], r14 + mov [rsp + 7 * 8], r15 + + // Save non-volatile xmm registers + movdqa xmmword ptr [rsp + 8 * 8 + 0 * 16], xmm6 + movdqa xmmword ptr [rsp + 8 * 8 + 1 * 16], xmm7 + movdqa xmmword ptr [rsp + 8 * 8 + 2 * 16], xmm8 + movdqa xmmword ptr [rsp + 8 * 8 + 3 * 16], xmm9 + movdqa xmmword ptr [rsp + 8 * 8 + 4 * 16], xmm10 + movdqa xmmword ptr [rsp + 8 * 8 + 5 * 16], xmm11 + movdqa xmmword ptr [rsp + 8 * 8 + 6 * 16], xmm12 + movdqa xmmword ptr [rsp + 8 * 8 + 7 * 16], xmm13 + movdqa xmmword ptr [rsp + 8 * 8 + 8 * 16], xmm14 + movdqa xmmword ptr [rsp + 8 * 8 + 9 * 16], xmm15 + + .ENDPROLOG + + // Set up a register state + mov rbx, HEX(A1A1A1A1A1A1A1A1) + mov rbp, HEX(A2A2A2A2A2A2A2A2) + mov rsi, HEX(A3A3A3A3A3A3A3A3) + mov rdi, HEX(A4A4A4A4A4A4A4A4) + mov r12, HEX(ACACACACACACACAC) + mov r13, HEX(ADADADADADADADAD) + mov r14, HEX(AEAEAEAEAEAEAEAE) + mov r15, HEX(AFAFAFAFAFAFAFAF) + movdqa xmm6, xmmword ptr xmm6_data[rip] + movdqa xmm7, xmmword ptr xmm7_data[rip] + movdqa xmm8, xmmword ptr xmm8_data[rip] + movdqa xmm9, xmmword ptr xmm9_data[rip] + movdqa xmm10, xmmword ptr xmm10_data[rip] + movdqa xmm11, xmmword ptr xmm11_data[rip] + movdqa xmm12, xmmword ptr xmm12_data[rip] + movdqa xmm13, xmmword ptr xmm13_data[rip] + movdqa xmm14, xmmword ptr xmm14_data[rip] + movdqa xmm15, xmmword ptr xmm15_data[rip] + + mov rdx, rsp + call r10 // _setjmp or _setjmpex +GLOBAL_LABEL setjmp_return_address + + // Restore non-volatile registers + mov rbx, [rsp + 0 * 8] + mov rbp, [rsp + 1 * 8] + mov rsi, [rsp + 2 * 8] + mov rdi, [rsp + 3 * 8] + mov r12, [rsp + 4 * 8] + mov r13, [rsp + 5 * 8] + mov r14, [rsp + 6 * 8] + mov r15, [rsp + 7 * 8] + + // Restore non-volatile xmm registers + movdqa xmm6, xmmword ptr [rsp + 8 * 8 + 0 * 16] + movdqa xmm7, xmmword ptr [rsp + 8 * 8 + 1 * 16] + movdqa xmm8, xmmword ptr [rsp + 8 * 8 + 2 * 16] + movdqa xmm9, xmmword ptr [rsp + 8 * 8 + 3 * 16] + movdqa xmm10, xmmword ptr [rsp + 8 * 8 + 4 * 16] + movdqa xmm11, xmmword ptr [rsp + 8 * 8 + 5 * 16] + movdqa xmm12, xmmword ptr [rsp + 8 * 8 + 6 * 16] + movdqa xmm13, xmmword ptr [rsp + 8 * 8 + 7 * 16] + movdqa xmm14, xmmword ptr [rsp + 8 * 8 + 8 * 16] + movdqa xmm15, xmmword ptr [rsp + 8 * 8 + 9 * 16] + + add rsp, 8 * 8 + 10 * 16 + 8 // Restore stack pointer + ret + +.ENDP + +END diff --git a/modules/rostests/apitests/crt/i386/setjmp_helper.s b/modules/rostests/apitests/crt/i386/setjmp_helper.s new file mode 100644 index 00000000000..093a7f48657 --- /dev/null +++ b/modules/rostests/apitests/crt/i386/setjmp_helper.s @@ -0,0 +1,79 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: Test helper for x86 setjmp + * COPYRIGHT: Copyright 2025 Timo Kreuzer + */ + +#include + +#ifdef TEST_UCRTBASE +#define __setjmp ___intrinsic_setjmp +#endif + +.code + +PUBLIC _get_sp +_get_sp: + lea eax, [esp + 4] + ret + +EXTERN __setjmp:PROC +PUBLIC _setjmp_return_address +EXTERN __setjmp3:PROC + +PUBLIC __setjmp1 +__setjmp1: + jmp __setjmp + +PUBLIC _call_setjmp +_call_setjmp: + push offset __setjmp + jmp _call_setjmp_common + +PUBLIC _call_setjmp3 +_call_setjmp3: + push offset __setjmp3 + jmp _call_setjmp_common + + +_call_setjmp_common: + // Save non-volatile registers + push ebp + push ebx + push edi + push esi + + // Set up a register state + mov ebp, HEX(A1A1A1A1) + mov ebx, HEX(A2A2A2A2) + mov edi, HEX(A3A3A3A3) + mov esi, HEX(A4A4A4A4) + + // First push parameters for _setjmp3 + push HEX(3456789A) // Param 3 + push HEX(23456789) // Param 2 + push HEX(12345678) // Param 1 + push HEX(00000007) // TryLevel + push HEX(00012345) // UnwindFunc + push HEX(00000005) // Count + + // Common parameter for both _setjmp and _setjmp3 + push dword ptr [esp + 48] + call dword ptr [esp + 44] +_setjmp_return_address: + + add esp, 28 + + // Restore non-volatile registers + pop esi + pop edi + pop ebx + pop ebp + + // Clean up the stack + add esp, 4 + + ret + +END diff --git a/modules/rostests/apitests/crt/setjmp.c b/modules/rostests/apitests/crt/setjmp.c index 165728d209b..bc4ce096fe3 100644 --- a/modules/rostests/apitests/crt/setjmp.c +++ b/modules/rostests/apitests/crt/setjmp.c @@ -13,6 +13,12 @@ #include #include +#if defined(_M_IX86) && !defined(_MSC_VER) +#define todo_pseh todo_if(1) +#else +#define todo_pseh +#endif + static jmp_buf g_jmp_buf; static void TEST_setjmp_normal(void) @@ -193,6 +199,362 @@ static void TEST_setjmp_zero_longjmp_check(void) } } +void call_setjmp(_JUMP_BUFFER *Buf); +ULONG_PTR get_sp(void); +extern char setjmp_return_address; +#ifdef _M_AMD64 +void call_setjmpex(_JUMP_BUFFER *Buf); +#elif defined(_M_IX86) +int _setjmp3(jmp_buf env, int count, /* void* UnwindFunc, unsigned TryLevel, */ ...); +int _setjmp1(jmp_buf env); // ASM call wrapper around _setjmp, which is an intrinsic on MSVC +void call_setjmp3(_JUMP_BUFFER *Buf); +#endif + +static void check_buffer_registers_(ULONG Line, _JUMP_BUFFER* Buf, ULONG_PTR Sp, void* Pc) +{ +#ifdef _M_AMD64 + ok_eq_hex64_(__FILE__, Line, Buf->Frame, Sp - 0xF0); + ok_eq_hex64_(__FILE__, Line, Buf->Rbx, 0xA1A1A1A1A1A1A1A1ULL); + ok_eq_hex64_(__FILE__, Line, Buf->Rsp, Sp - 0xF0); + ok_eq_hex64_(__FILE__, Line, Buf->Rbp, 0xA2A2A2A2A2A2A2A2ULL); + ok_eq_hex64_(__FILE__, Line, Buf->Rsi, 0xA3A3A3A3A3A3A3A3ULL); + ok_eq_hex64_(__FILE__, Line, Buf->Rdi, 0xA4A4A4A4A4A4A4A4ULL); + ok_eq_hex64_(__FILE__, Line, Buf->R12, 0xACACACACACACACACULL); + ok_eq_hex64_(__FILE__, Line, Buf->R13, 0xADADADADADADADADULL); + ok_eq_hex64_(__FILE__, Line, Buf->R14, 0xAEAEAEAEAEAEAEAEULL); + ok_eq_hex64_(__FILE__, Line, Buf->R15, 0xAFAFAFAFAFAFAFAFULL); + ok_eq_hex64_(__FILE__, Line, Buf->Rip, (ULONG64)Pc); + ok_eq_hex_(__FILE__, Line, Buf->MxCsr, 0x00001f80); + ok_eq_hex64_(__FILE__, Line, Buf->FpCsr, 0x27F); + ok_eq_hex64_(__FILE__, Line, Buf->Spare, 0xCCCC); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm6.Part[0], 0x0606060606060606ULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm6.Part[1], 0x1616161616161616ULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm7.Part[0], 0x0707070707070707ULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm7.Part[1], 0x1717171717171717ULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm8.Part[0], 0x0808080808080808ULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm8.Part[1], 0x1818181818181818ULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm9.Part[0], 0x0909090909090909ULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm9.Part[1], 0x1919191919191919ULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm10.Part[0], 0x0A0A0A0A0A0A0A0AULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm10.Part[1], 0x1A1A1A1A1A1A1A1AULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm11.Part[0], 0x0B0B0B0B0B0B0B0BULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm11.Part[1], 0x1B1B1B1B1B1B1B1BULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm12.Part[0], 0x0C0C0C0C0C0C0C0CULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm12.Part[1], 0x1C1C1C1C1C1C1C1CULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm13.Part[0], 0x0D0D0D0D0D0D0D0DULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm13.Part[1], 0x1D1D1D1D1D1D1D1DULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm14.Part[0], 0x0E0E0E0E0E0E0E0EULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm14.Part[1], 0x1E1E1E1E1E1E1E1EULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm15.Part[0], 0x0F0F0F0F0F0F0F0FULL); + ok_eq_hex64_(__FILE__, Line, Buf->Xmm15.Part[1], 0x1F1F1F1F1F1F1F1FULL); +#elif defined(_M_IX86) + ok_eq_hex_(__FILE__, Line, Buf->Ebp, 0xA1A1A1A1ul); + ok_eq_hex_(__FILE__, Line, Buf->Ebx, 0xA2A2A2A2ul); + ok_eq_hex_(__FILE__, Line, Buf->Edi, 0xA3A3A3A3ul); + ok_eq_hex_(__FILE__, Line, Buf->Esi, 0xA4A4A4A4ul); + ok_eq_hex_(__FILE__, Line, Buf->Esp, Sp - 0x38); + ok_eq_hex_(__FILE__, Line, Buf->Eip, (ULONG)Pc); +#endif +} +#define check_buffer_registers(Buf, Sp, Pc) \ + check_buffer_registers_(__LINE__, Buf, Sp, Pc) + +static void TEST_buffer_contents(void) +{ + _JUMP_BUFFER buf; + + memset(&buf, 0xCC, sizeof(buf)); + call_setjmp(&buf); + check_buffer_registers(&buf, get_sp(), &setjmp_return_address); + +#ifdef _M_AMD64 + + memset(&buf, 0xCC, sizeof(buf)); + call_setjmpex(&buf); + check_buffer_registers(&buf, get_sp(), &setjmp_return_address); + +#elif defined(_M_IX86) + + ok_eq_hex(buf.Registration, __readfsdword(0)); + todo_pseh ok_eq_hex(buf.TryLevel, 0xFFFFFFFF); + ok_eq_hex(buf.Cookie, 0xCCCCCCCC); + ok_eq_hex(buf.UnwindFunc, 0xCCCCCCCC); + ok_eq_hex(buf.UnwindData[0], 0xCCCCCCCC); + ok_eq_hex(buf.UnwindData[1], 0xCCCCCCCC); + ok_eq_hex(buf.UnwindData[2], 0xCCCCCCCC); + ok_eq_hex(buf.UnwindData[3], 0xCCCCCCCC); + ok_eq_hex(buf.UnwindData[4], 0xCCCCCCCC); + ok_eq_hex(buf.UnwindData[5], 0xCCCCCCCC); + + // Temporarily remove the SEH registration (__writefsdword(0, ...) is not allowed with MSVC) + PULONG ExceptionRegistrationPtr = (PULONG)NtCurrentTeb(); + ULONG Registration = *ExceptionRegistrationPtr; + *ExceptionRegistrationPtr = 0xFFFFFFFF; + + memset(&buf, 0xCC, sizeof(buf)); + call_setjmp(&buf); + ok_eq_hex(buf.Registration, 0xFFFFFFFF); + ok_eq_hex(buf.TryLevel, 0xFFFFFFFF); + ok_eq_hex(buf.Cookie, 0xCCCCCCCC); + ok_eq_hex(buf.UnwindFunc, 0xCCCCCCCC); + + // Restore the SEH registration + *ExceptionRegistrationPtr = Registration; + + _SEH2_TRY + { + Registration = __readfsdword(0); + _SEH2_TRY + { + ok_eq_hex(Registration, __readfsdword(0)); + memset(&buf, 0xCC, sizeof(buf)); + call_setjmp(&buf); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* This is to ensure that the exception handler is not optimized out. */ + ok_int(GetExceptionCode(), 0); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* This is to ensure that the exception handler is not optimized out. */ + ok_int(GetExceptionCode(), 0); + } + _SEH2_END; + + ok_eq_hex(buf.Registration, Registration); + todo_pseh ok_eq_hex(buf.TryLevel, 1); + ok_eq_hex(buf.Cookie, 0xCCCCCCCC); + ok_eq_hex(buf.UnwindFunc, 0xCCCCCCCC); +#endif +} + +#ifdef _M_IX86 + +__declspec(noinline) +static void Test_setjmp1_longjmp_inside_SEH(void) +{ + jmp_buf buf; + int finally_called = 0; + + // Use the legacy _setjmp + int longjmp_value = _setjmp1(buf); + if (longjmp_value == 0) + { + _SEH2_TRY + { + longjmp(buf, 0x12345678); + } + _SEH2_FINALLY + { + finally_called = 1; + } + _SEH2_END; + } + + ok_eq_int(longjmp_value, 0x12345678); + ok_eq_int(finally_called, 1); +} + +__declspec(noinline) +static int Test_setjmp1_inner(void) +{ + jmp_buf buf; + + int longjmp_value = _setjmp1(buf); + if (longjmp_value == 0) + { + longjmp(buf, 0x12345678); + } + return longjmp_value; +} + +__declspec(noinline) +static void Test_setjmp1_external_inside_SEH(void) +{ + volatile int ret = 0; + _SEH2_TRY + { + _SEH2_TRY + { + ret = Test_setjmp1_inner(); + } + _SEH2_FINALLY + { + if (_SEH2_AbnormalTermination()) + ret = -1; + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = -2; + } + _SEH2_END; + ok_eq_int(ret, 0x12345678); +} + +#if 0 // This actually crashes on Windows! +__declspec(noinline) +void Test_setjmp1_no_SEH_registration(void) +{ + jmp_buf buf; + + // Temporarily remove the SEH registration + PULONG ExceptionRegistrationPtr = (PULONG)NtCurrentTeb(); + ULONG Registration = *ExceptionRegistrationPtr; + *ExceptionRegistrationPtr = 0xFFFFFFFF; + + // This will save 0xFFFFFFFF in the Registration field + int longjmp_value = _setjmp1(buf); + if (longjmp_value == 0) + { + // This will check if Registration is 0(!) and if not, it will + // call _local_unwind2, which will dereference the Registration + // and crash. + longjmp(buf, 1); + } + + ok_eq_int(longjmp_value, 1); + + // Restore the SEH registration + *ExceptionRegistrationPtr = Registration; +} +#endif + +__declspec(noinline) +static void Test_setjmp3(void) +{ + ULONG BufferData[18]; + _JUMP_BUFFER* Buf = (_JUMP_BUFFER*)&BufferData; + + memset(&BufferData, 0xCC, sizeof(BufferData)); + call_setjmp3(Buf); + check_buffer_registers(Buf, get_sp(), &setjmp_return_address); + ok_eq_hex(Buf->Registration, __readfsdword(0)); + ok_eq_hex(Buf->TryLevel, 7); + ok_eq_hex(Buf->Cookie, 0x56433230); + ok_eq_hex(Buf->UnwindFunc, 0x00012345); + ok_eq_hex(Buf->UnwindData[0], 0x12345678); + ok_eq_hex(Buf->UnwindData[1], 0x23456789); + ok_eq_hex(Buf->UnwindData[2], 0x3456789a); + ok_eq_hex(Buf->UnwindData[3], 0xCCCCCCCC); + ok_eq_hex(Buf->UnwindData[4], 0xCCCCCCCC); + ok_eq_hex(Buf->UnwindData[5], 0xCCCCCCCC); + + memset(&BufferData, 0xCC, sizeof(BufferData)); + _setjmp3((int*)Buf, 0, (void*)0x12345, 3, 0xA1A1A1A1, 0xA2A2A2A2, 0xA3A3A3A3, 0xA4A4A4A4); + ok_eq_hex(Buf->Registration, __readfsdword(0)); + ok_eq_hex(Buf->TryLevel, 0); + ok_eq_hex(Buf->Cookie, 0x56433230); + ok_eq_hex(Buf->UnwindFunc, 0x00000000); + ok_eq_hex(Buf->UnwindData[0], 0xCCCCCCCC); + ok_eq_hex(Buf->UnwindData[1], 0xCCCCCCCC); + ok_eq_hex(Buf->UnwindData[2], 0xCCCCCCCC); + ok_eq_hex(Buf->UnwindData[3], 0xCCCCCCCC); + ok_eq_hex(Buf->UnwindData[4], 0xCCCCCCCC); + ok_eq_hex(Buf->UnwindData[5], 0xCCCCCCCC); + + static ULONG Data[4] = { 0x0123, 0x1234, 0x2345, 0x3456 }; + memset(&BufferData, 0xCC, sizeof(BufferData)); + _setjmp3((int*)Buf, 1, Data, 7, 0xA1A1A1A1, 0xA2A2A2A2, 0xA3A3A3A3, 0xA4A4A4A4); + ok_eq_hex(Buf->Registration, __readfsdword(0)); + ok_eq_hex(Buf->TryLevel, 0x00003456); + ok_eq_hex(Buf->Cookie, 0x56433230); + ok_eq_hex(Buf->UnwindFunc, (ULONG)Data); + ok_eq_hex(Buf->UnwindData[0], 0xCCCCCCCC); + + memset(&BufferData, 0xCC, sizeof(BufferData)); + _setjmp3((int*)Buf, 2, Data, 7, 0xA1A1A1A1, 0xA2A2A2A2, 0xA3A3A3A3, 0xA4A4A4A4); + ok_eq_hex(Buf->Registration, __readfsdword(0)); + ok_eq_hex(Buf->TryLevel, 7); + ok_eq_hex(Buf->Cookie, 0x56433230); + ok_eq_hex(Buf->UnwindFunc, (ULONG)Data); + ok_eq_hex(Buf->UnwindData[0], 0xCCCCCCCC); + + memset(&BufferData, 0xCC, sizeof(BufferData)); + _setjmp3((int*)Buf, 3, Data, 7, 0xA1A1A1A1, 0xA2A2A2A2, 0xA3A3A3A3, 0xA4A4A4A4); + ok_eq_hex(Buf->Registration, __readfsdword(0)); + ok_eq_hex(Buf->TryLevel, 7); + ok_eq_hex(Buf->Cookie, 0x56433230); + ok_eq_hex(Buf->UnwindFunc, (ULONG)Data); + ok_eq_hex(Buf->UnwindData[0], 0xA1A1A1A1); + ok_eq_hex(Buf->UnwindData[1], 0xCCCCCCCC); + + memset(&BufferData, 0xCC, sizeof(BufferData)); + _setjmp3((int*)Buf, 11, (PVOID)0xdeadbeef, 7, 0xA1A1A1A1, 0xA2A2A2A2, 0xA3A3A3A3, 0xA4A4A4A4, 0xA5A5A5A5, 0xA6A6A6A6, 0xA7A7A7A7, 0xA8A8A8A8, 0xA9A9A9A9); + ok_eq_hex(Buf->Registration, __readfsdword(0)); + ok_eq_hex(Buf->TryLevel, 7); + ok_eq_hex(Buf->Cookie, 0x56433230); + ok_eq_hex(Buf->UnwindFunc, 0xdeadbeef); + ok_eq_hex(Buf->UnwindData[0], 0xA1A1A1A1); + ok_eq_hex(Buf->UnwindData[1], 0xA2A2A2A2); + ok_eq_hex(Buf->UnwindData[2], 0xA3A3A3A3); + ok_eq_hex(Buf->UnwindData[3], 0xA4A4A4A4); + ok_eq_hex(Buf->UnwindData[4], 0xA5A5A5A5); + ok_eq_hex(Buf->UnwindData[5], 0xA6A6A6A6); + ok_eq_hex(BufferData[16], 0xCCCCCCCC); + ok_eq_hex(BufferData[17], 0xCCCCCCCC); + + // Temporarily remove the SEH registration + PULONG ExceptionRegistrationPtr = (PULONG)NtCurrentTeb(); + ULONG Registration = *ExceptionRegistrationPtr; + *ExceptionRegistrationPtr = 0xFFFFFFFF; + + memset(&BufferData, 0xCC, sizeof(BufferData)); + _setjmp3((int*)Buf, 11, (PVOID)0xdeadbeef, 7, 0xA1A1A1A1, 0xA2A2A2A2, 0xA3A3A3A3, 0xA4A4A4A4, 0xA5A5A5A5, 0xA6A6A6A6, 0xA7A7A7A7, 0xA8A8A8A8, 0xA9A9A9A9); + ok_eq_hex(Buf->Registration, 0xFFFFFFFF); + ok_eq_hex(Buf->TryLevel, 0xFFFFFFFF); + ok_eq_hex(Buf->Cookie, 0x56433230); + ok_eq_hex(Buf->UnwindFunc, 0x00000000); + ok_eq_hex(Buf->UnwindData[0], 0xCCCCCCCC); + ok_eq_hex(Buf->UnwindData[1], 0xCCCCCCCC); + + int value = _setjmp3((int*)Buf, 0); + if (value == 0) + { + ok_eq_hex(Buf->Registration, 0xFFFFFFFF); + ok_eq_hex(Buf->TryLevel, 0xFFFFFFFF); + ok_eq_hex(Buf->Cookie, 0x56433230); + ok_eq_hex(Buf->UnwindFunc, 0x00000000); + ok_eq_hex(Buf->UnwindData[0], 0xCCCCCCCC); + ok_eq_hex(Buf->UnwindData[1], 0xCCCCCCCC); + longjmp((int*)Buf, 0xBEEFCAFE); + ok(0, "Should not get here\n"); + } + ok_int(value, 0xBEEFCAFE); + + // Restore the SEH registration + *ExceptionRegistrationPtr = Registration; +} + +__declspec(noinline) +void Test_setjmp3_with_SEH(void) +{ + _JUMP_BUFFER buf; + volatile int dummy; + + _SEH2_TRY + { + dummy = 0; + (void)dummy; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + } + _SEH2_END; + + memset(&buf, 0xCC, sizeof(buf)); + _setjmp3((int*)& buf, 0, (void*)0x12345, 3, 0xA1A1A1A1, 0xA2A2A2A2, 0xA3A3A3A3, 0xA4A4A4A4); + ok_eq_hex(buf.Registration, __readfsdword(0)); + todo_pseh ok_eq_hex(buf.TryLevel, 0xffffffff); +} + +#endif // _M_IX86 + +#undef setjmp START_TEST(setjmp) { ZeroMemory(&s_check_points, sizeof(s_check_points)); @@ -202,6 +564,14 @@ START_TEST(setjmp) TEST_setjmp_return_check(); TEST_setjmp_longjmp_integration(); TEST_setjmp_zero_longjmp_check(); + TEST_buffer_contents(); +#ifdef _M_IX86 + Test_setjmp1_longjmp_inside_SEH(); + Test_setjmp1_external_inside_SEH(); + //Test_setjmp1_no_SEH_registration(); + Test_setjmp3(); + Test_setjmp3_with_SEH(); +#endif /* _M_IX86 */ #define DO_COME(number) \ ok(s_check_points[number], "CheckPoint #%d: Didn't reach\n", number) diff --git a/modules/rostests/apitests/crt/static_crt_apitest.cmake b/modules/rostests/apitests/crt/static_crt_apitest.cmake index 4edc08e388b..6bd8bf2fe0a 100644 --- a/modules/rostests/apitests/crt/static_crt_apitest.cmake +++ b/modules/rostests/apitests/crt/static_crt_apitest.cmake @@ -40,9 +40,20 @@ elseif(ARCH STREQUAL "arm") ) endif() -add_executable(static_crt_apitest EXCLUDE_FROM_ALL testlist.c ${SOURCE_STATIC}) +if(ARCH STREQUAL "i386") + list(APPEND ASM_SOURCE_STATIC + i386/setjmp_helper.s + ) +elseif(ARCH STREQUAL "amd64") + list(APPEND ASM_SOURCE_STATIC + amd64/setjmp_helper.s + ) +endif() +add_asm_files(crt_test_asm ${ASM_SOURCE_STATIC}) + +add_executable(static_crt_apitest EXCLUDE_FROM_ALL testlist.c ${SOURCE_STATIC} ${crt_test_asm}) target_compile_definitions(static_crt_apitest PRIVATE TEST_STATIC_CRT _CRTBLD wine_dbgstr_an=wine_dbgstr_an_ wine_dbgstr_wn=wine_dbgstr_wn_) -target_link_libraries(static_crt_apitest crt wine ${PSEH_LIB}) +target_link_libraries(static_crt_apitest setjmp crt wine ${PSEH_LIB}) set_module_type(static_crt_apitest win32cui) add_importlibs(static_crt_apitest kernel32 ntdll) add_rostests_file(TARGET static_crt_apitest) diff --git a/modules/rostests/apitests/crtdll/CMakeLists.txt b/modules/rostests/apitests/crtdll/CMakeLists.txt index fd695d8c637..b4c5356cfa9 100644 --- a/modules/rostests/apitests/crtdll/CMakeLists.txt +++ b/modules/rostests/apitests/crtdll/CMakeLists.txt @@ -19,7 +19,17 @@ list(APPEND SOURCE_CRTDLL ../crt/wctomb.c ) -add_executable(crtdll_apitest testlist.c ${SOURCE_CRTDLL}) +if(ARCH STREQUAL "i386") + add_asm_files(crtdll_apitest_asm + ../crt/i386/setjmp_helper.s + ) +elseif(ARCH STREQUAL "amd64") + add_asm_files(crtdll_apitest_asm + ../crt/amd64/setjmp_helper.s + ) +endif() + +add_executable(crtdll_apitest testlist.c ${SOURCE_CRTDLL} ${crtdll_apitest_asm}) target_compile_definitions(crtdll_apitest PRIVATE TEST_CRTDLL) target_link_libraries(crtdll_apitest wine ${PSEH_LIB}) set_module_type(crtdll_apitest win32cui) diff --git a/modules/rostests/apitests/msvcrt/CMakeLists.txt b/modules/rostests/apitests/msvcrt/CMakeLists.txt index d97a583910c..015c8d23fca 100644 --- a/modules/rostests/apitests/msvcrt/CMakeLists.txt +++ b/modules/rostests/apitests/msvcrt/CMakeLists.txt @@ -54,6 +54,13 @@ if(ARCH STREQUAL "i386") list(APPEND SOURCE_CRT_TESTS ../crt/__getmainargs.c # FIXME: Moved here because it doesn't work on x64 ) + list(APPEND ASM_SOURCE_CRT_TESTS + ../crt/i386/setjmp_helper.s + ) +elseif(ARCH STREQUAL "amd64") + list(APPEND ASM_SOURCE_CRT_TESTS + ../crt/amd64/setjmp_helper.s + ) elseif(ARCH STREQUAL "arm") list(APPEND SOURCE_CRT_TESTS ../crt/__rt_div.c @@ -61,9 +68,11 @@ elseif(ARCH STREQUAL "arm") ../crt/__64tof.c ) endif() +add_asm_files(crt_asm ${ASM_SOURCE_CRT_TESTS}) list(APPEND SOURCE ${SOURCE_CRT_TESTS} + ${crt_asm} CommandLine.c ieee.c popen.c @@ -71,6 +80,7 @@ list(APPEND SOURCE testlist.c) add_executable(msvcrt_apitest ${SOURCE}) +add_dependencies(msvcrt_apitest asm) target_compile_definitions(msvcrt_apitest PRIVATE TEST_MSVCRT) target_link_libraries(msvcrt_apitest wine ${PSEH_LIB}) set_module_type(msvcrt_apitest win32cui) diff --git a/modules/rostests/apitests/ntdll/CMakeLists.txt b/modules/rostests/apitests/ntdll/CMakeLists.txt index 2646f181c68..3e0e0df2c34 100644 --- a/modules/rostests/apitests/ntdll/CMakeLists.txt +++ b/modules/rostests/apitests/ntdll/CMakeLists.txt @@ -139,9 +139,15 @@ list(APPEND SOURCE precomp.h) if(ARCH STREQUAL "i386") - add_asm_files(ntdll_apitest_asm i386/NtContinue.S) + add_asm_files(ntdll_apitest_asm + ../crt/i386/setjmp_helper.s + i386/NtContinue.S + ) elseif(ARCH STREQUAL "amd64") - add_asm_files(ntdll_apitest_asm amd64/NtContinue.S) + add_asm_files(ntdll_apitest_asm + ../crt/amd64/setjmp_helper.s + amd64/NtContinue.S + ) endif() list(APPEND PCH_SKIP_SOURCE diff --git a/modules/rostests/apitests/ucrtbase/CMakeLists.txt b/modules/rostests/apitests/ucrtbase/CMakeLists.txt index 5300f868a67..58fce55f0cb 100644 --- a/modules/rostests/apitests/ucrtbase/CMakeLists.txt +++ b/modules/rostests/apitests/ucrtbase/CMakeLists.txt @@ -22,13 +22,24 @@ list(APPEND SOURCE ../crt/log.c ../crt/log10.c ../crt/round.c + ../crt/setjmp.c ../crt/sin.c ../crt/sqrt.c ../crt/tan.c testlist.c ) -add_executable(ucrtbase_apitest ${SOURCE}) +if(ARCH STREQUAL "i386") + add_asm_files(ucrtbase_apitest_asm + ../crt/i386/setjmp_helper.s + ) +elseif(ARCH STREQUAL "amd64") + add_asm_files(ucrtbase_apitest_asm + ../crt/amd64/setjmp_helper.s + ) +endif() + +add_executable(ucrtbase_apitest ${SOURCE} ${ucrtbase_apitest_asm}) set_module_type(ucrtbase_apitest win32cui) target_link_libraries(ucrtbase_apitest ${PSEH_LIB} chkstk) @@ -37,5 +48,5 @@ if(NOT MSVC) target_link_libraries(ucrtbase_apitest -lgcc) endif() -add_importlibs(ucrtbase_apitest ucrtbase kernel32 ntdll) +add_importlibs(ucrtbase_apitest ucrtbase kernel32) add_rostests_file(TARGET ucrtbase_apitest) diff --git a/modules/rostests/apitests/ucrtbase/testlist.c b/modules/rostests/apitests/ucrtbase/testlist.c index 79791c37319..98688e966f2 100644 --- a/modules/rostests/apitests/ucrtbase/testlist.c +++ b/modules/rostests/apitests/ucrtbase/testlist.c @@ -14,6 +14,7 @@ extern void func_exp(void); extern void func_log(void); extern void func_log10(void); extern void func_round(void); +extern void func_setjmp(void); extern void func_sin(void); extern void func_sqrt(void); extern void func_tan(void); @@ -32,6 +33,7 @@ const struct test winetest_testlist[] = { "log", func_log }, { "log10", func_log10 }, { "round", func_round }, + { "setjmp", func_setjmp }, { "sin", func_sin }, { "sqrt", func_sqrt }, { "tan", func_tan },