[CRT_APITEST] Add more tests for _setjmp

This commit is contained in:
Timo Kreuzer
2025-05-29 00:29:56 +03:00
parent d7761b1296
commit 5b2091e37c
10 changed files with 650 additions and 7 deletions

View File

@@ -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)

View File

@@ -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 <timo.kreuzer@reactos.org>
*/
#include <asm.inc>
#include <ksamd64.inc>
#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

View File

@@ -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 <timo.kreuzer@reactos.org>
*/
#include <asm.inc>
#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

View File

@@ -13,6 +13,12 @@
#include <assert.h>
#include <rtlfuncs.h>
#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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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 },