mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-27 11:53:32 +00:00
346 lines
14 KiB
C
346 lines
14 KiB
C
/*
|
|
* PROJECT: ReactOS api tests
|
|
* LICENSE: See COPYING in the top level directory
|
|
* PURPOSE: Test for NtCreateThread
|
|
* PROGRAMMER: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
|
* PROGRAMMER: Timo Kreuzer <[email protected]>
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
PVOID TestThreadProcPtr;
|
|
CONTEXT TestThreadStartupContext;
|
|
DECLSPEC_ALIGN(16) UCHAR TestThreadStartupStack[PAGE_SIZE];
|
|
BOOLEAN TestThreadFunctionCalled;
|
|
extern void ThreadStartupThunk(void*);
|
|
|
|
#define RPL_MASK 0x0003
|
|
#define MODE_MASK 0x0001
|
|
#define EFLAGS_INTERRUPT_MASK 0x200L
|
|
#define KGDT_R3_CODE 0x0018
|
|
#define KGDT_R3_DATA 0x0020
|
|
#define KGDT_R3_TEB 0x0038
|
|
#define KGDT64_R3_CMCODE 0x0020
|
|
#define KGDT64_R3_DATA 0x0028
|
|
#define KGDT64_R3_CODE 0x0030
|
|
#define KGDT64_R3_CMTEB 0x0050
|
|
|
|
static
|
|
VOID
|
|
InitializeTestContext(PCONTEXT Context)
|
|
{
|
|
RtlFillMemory(Context, sizeof(*Context), 0xAA);
|
|
|
|
Context->ContextFlags = CONTEXT_ALL;
|
|
|
|
#ifdef _M_AMD64
|
|
|
|
/* Control */
|
|
Context->Rsp = (ULONG64)(TestThreadStartupStack + PAGE_SIZE - 16);
|
|
Context->Rip = (ULONG64)ThreadStartupThunk;
|
|
|
|
/* Set Eflags. These get sanitized, but 0x100 (trap flag) makes it trap instantly. */
|
|
Context->EFlags = 0xFFFFFFFF;
|
|
Context->EFlags &= ~0x100;
|
|
|
|
/* Integer (these are copied) */
|
|
Context->Rax = 0xF000000000000000;
|
|
Context->Rcx = 0xF000000000000001;
|
|
Context->Rdx = 0xF000000000000002;
|
|
Context->Rbx = 0xF000000000000003;
|
|
Context->Rbp = 0xF000000000000005;
|
|
Context->Rsi = 0xF000000000000006;
|
|
Context->Rdi = 0xF000000000000007;
|
|
Context->R8 = 0xF000000000000008;
|
|
Context->R9 = 0xF000000000000009;
|
|
Context->R10 = 0xF00000000000000A;
|
|
Context->R11 = 0xF00000000000000B;
|
|
Context->R12 = 0xF00000000000000C;
|
|
Context->R13 = 0xF00000000000000D;
|
|
Context->R14 = 0xF00000000000000E;
|
|
Context->R15 = 0xF00000000000000F;
|
|
|
|
#elif defined(_M_IX86)
|
|
|
|
/* Control */
|
|
Context->Esp = (ULONG)(TestThreadStartupStack + PAGE_SIZE - 16);
|
|
Context->Eip = (ULONG)ThreadStartupThunk;
|
|
|
|
/* Set Eflags. These get sanitized, but 0x100 (trap flag) makes it trap instantly. */
|
|
Context->EFlags = 0xFFFFFFFF;
|
|
Context->EFlags &= ~0x100; // Disable trap flag, because it would make the thread trap instantly
|
|
Context->EFlags &= ~0x00020000; // Disable V86 flag
|
|
|
|
/* Integer (these are copied) */
|
|
Context->Eax = 0xF0000000;
|
|
Context->Ecx = 0xF0000001;
|
|
Context->Edx = 0xF0000002;
|
|
Context->Ebx = 0xF0000003;
|
|
Context->Ebp = 0xF0000005;
|
|
Context->Esi = 0xF0000006;
|
|
Context->Edi = 0xF0000007;
|
|
|
|
/* FIXME: Initialize segments to prevent ReactOS from crashing in the kernel */
|
|
Context->SegCs = KGDT_R3_CODE | RPL_MASK;
|
|
Context->SegSs = KGDT_R3_DATA | RPL_MASK;
|
|
Context->SegDs = KGDT_R3_DATA | RPL_MASK;
|
|
Context->SegEs = KGDT_R3_DATA | RPL_MASK;
|
|
Context->SegFs = KGDT_R3_TEB | RPL_MASK;
|
|
Context->SegGs = 0;
|
|
|
|
#else
|
|
|
|
#pragma message("Missing CONTEXT setup in NtCreateThread test")
|
|
ASSERT(FALSE);
|
|
|
|
#endif
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
TestThreadProc(IN PVOID StartContext)
|
|
{
|
|
TestThreadFunctionCalled = TRUE;
|
|
|
|
#if defined(_M_IX86) || defined(_M_AMD64)
|
|
CONTEXT Context;
|
|
|
|
/* Get the debug registers and floating point */
|
|
Context.ContextFlags = CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT;
|
|
GetThreadContext(NtCurrentThread(), &Context);
|
|
TestThreadStartupContext.Dr0 = Context.Dr0;
|
|
TestThreadStartupContext.Dr1 = Context.Dr1;
|
|
TestThreadStartupContext.Dr2 = Context.Dr2;
|
|
TestThreadStartupContext.Dr3 = Context.Dr3;
|
|
TestThreadStartupContext.Dr6 = Context.Dr6;
|
|
TestThreadStartupContext.Dr7 = Context.Dr7;
|
|
#if defined(_M_IX86)
|
|
TestThreadStartupContext.FloatSave = Context.FloatSave;
|
|
#endif
|
|
#endif
|
|
|
|
/* Terminate current thread */
|
|
NtTerminateThread(NtCurrentThread(), STATUS_SUCCESS);
|
|
}
|
|
|
|
START_TEST(NtCreateThread)
|
|
{
|
|
NTSTATUS Status;
|
|
INITIAL_TEB InitialTeb;
|
|
HANDLE ThreadHandle;
|
|
OBJECT_ATTRIBUTES Attributes;
|
|
DECLSPEC_ALIGN(16) ULONG_PTR Stack[128];
|
|
PULONG_PTR StackPtr = &Stack[ARRAYSIZE(Stack) - 2];
|
|
CONTEXT Context;
|
|
CLIENT_ID ClientId;
|
|
|
|
BOOL IsWow64 = FALSE;
|
|
IsWow64Process(GetCurrentProcess(), &IsWow64);
|
|
|
|
InitializeObjectAttributes(&Attributes, NULL, 0, NULL, NULL);
|
|
ZeroMemory(&InitialTeb, sizeof(INITIAL_TEB));
|
|
|
|
Status = NtCreateThread(&ThreadHandle,
|
|
0,
|
|
&Attributes,
|
|
NtCurrentProcess(),
|
|
NULL,
|
|
(PCONTEXT)0x70000000, /* Aligned usermode address */
|
|
&InitialTeb,
|
|
FALSE);
|
|
|
|
ok_hex(Status, STATUS_ACCESS_VIOLATION);
|
|
|
|
InitialTeb.PreviousStackBase = NULL;
|
|
InitialTeb.PreviousStackLimit = NULL;
|
|
InitialTeb.StackBase = StackPtr;
|
|
InitialTeb.StackLimit = Stack;
|
|
InitialTeb.AllocatedStackBase = Stack;
|
|
|
|
TestThreadProcPtr = TestThreadProc;
|
|
|
|
RtlFillMemory(&TestThreadStartupContext, sizeof(TestThreadStartupContext), 0xCC);
|
|
InitializeTestContext(&Context);
|
|
|
|
Status = NtCreateThread(&ThreadHandle,
|
|
THREAD_ALL_ACCESS,
|
|
NULL,
|
|
NtCurrentProcess(),
|
|
&ClientId,
|
|
&Context,
|
|
&InitialTeb,
|
|
TRUE);
|
|
ok_eq_hex(Status, STATUS_SUCCESS);
|
|
|
|
NtResumeThread(ThreadHandle, NULL);
|
|
WaitForSingleObject(ThreadHandle, INFINITE);
|
|
CloseHandle(ThreadHandle);
|
|
|
|
ok_eq_bool(TestThreadFunctionCalled, TRUE);
|
|
TestThreadFunctionCalled = FALSE;
|
|
|
|
#ifdef _M_AMD64
|
|
|
|
/* Control */
|
|
ok_eq_hex64(TestThreadStartupContext.Rsp, Context.Rsp - 0x28);
|
|
ok_eq_hex64(TestThreadStartupContext.SegCs, 0x0033);
|
|
ok_eq_hex64(TestThreadStartupContext.EFlags, 0x200ED7);
|
|
ok_eq_hex(TestThreadStartupContext.SegSs, 0x0002B);
|
|
|
|
/* Integer (copied) */
|
|
ok_eq_hex64(TestThreadStartupContext.Rax, Context.Rax);
|
|
ok_eq_hex64(TestThreadStartupContext.Rcx, Context.Rcx);
|
|
ok_eq_hex64(TestThreadStartupContext.Rdx, Context.Rdx);
|
|
ok_eq_hex64(TestThreadStartupContext.Rbx, Context.Rbx);
|
|
ok_eq_hex64(TestThreadStartupContext.Rbp, (GetNTVersion() >= _WIN32_WINNT_WIN10) ? Context.Rbp : 0);
|
|
ok_eq_hex64(TestThreadStartupContext.Rsi, Context.Rsi);
|
|
ok_eq_hex64(TestThreadStartupContext.Rdi, Context.Rdi);
|
|
ok_eq_hex64(TestThreadStartupContext.R8, Context.R8);
|
|
ok_eq_hex64(TestThreadStartupContext.R9, Context.R9);
|
|
ok_eq_hex64(TestThreadStartupContext.R10, Context.R10);
|
|
ok_eq_hex64(TestThreadStartupContext.R11, Context.R11);
|
|
ok_eq_hex64(TestThreadStartupContext.R12, Context.R12);
|
|
ok_eq_hex64(TestThreadStartupContext.R13, Context.R13);
|
|
ok_eq_hex64(TestThreadStartupContext.R14, Context.R14);
|
|
ok_eq_hex64(TestThreadStartupContext.R15, Context.R15);
|
|
|
|
/* Segments (hardcoded) */
|
|
ok_eq_hex(TestThreadStartupContext.SegDs, KGDT64_R3_DATA | RPL_MASK);
|
|
ok_eq_hex(TestThreadStartupContext.SegEs, KGDT64_R3_DATA | RPL_MASK);
|
|
ok_eq_hex(TestThreadStartupContext.SegFs, KGDT64_R3_CMTEB | RPL_MASK);
|
|
ok_eq_hex(TestThreadStartupContext.SegGs, KGDT64_R3_DATA | RPL_MASK);
|
|
|
|
/* Floating point (hardcoded) */
|
|
ok_eq_hex64(TestThreadStartupContext.MxCsr, INITIAL_MXCSR);
|
|
ok_eq_hex(TestThreadStartupContext.FltSave.ControlWord, INITIAL_FPCSR);
|
|
ok_eq_hex(TestThreadStartupContext.FltSave.StatusWord, 0x0000);
|
|
ok_eq_hex(TestThreadStartupContext.FltSave.TagWord, 0x00);
|
|
ok_eq_hex(TestThreadStartupContext.FltSave.Reserved1, 0x00);
|
|
ok_eq_hex(TestThreadStartupContext.FltSave.ErrorOpcode, 0x0000);
|
|
ok_eq_hex(TestThreadStartupContext.FltSave.ErrorOffset, 0x00000000);
|
|
ok_eq_hex(TestThreadStartupContext.FltSave.ErrorSelector, 0x0000);
|
|
ok_eq_hex(TestThreadStartupContext.FltSave.Reserved2, 0x0000);
|
|
ok_eq_hex(TestThreadStartupContext.FltSave.DataOffset, 0x00000000);
|
|
ok_eq_hex(TestThreadStartupContext.FltSave.DataSelector, 0x0000);
|
|
ok_eq_hex(TestThreadStartupContext.FltSave.Reserved3, 0x0000);
|
|
ok_eq_hex(TestThreadStartupContext.FltSave.MxCsr, INITIAL_MXCSR);
|
|
ok_eq_hex(TestThreadStartupContext.FltSave.MxCsr_Mask, 0x0002FFFF);
|
|
for (ULONG i = 0; i < ARRAYSIZE(TestThreadStartupContext.FltSave.FloatRegisters); i++)
|
|
{
|
|
ok_eq_hex64(TestThreadStartupContext.FltSave.FloatRegisters[i].Low, 0x0000000000000000ull);
|
|
ok_eq_hex64(TestThreadStartupContext.FltSave.FloatRegisters[i].High, 0x0000000000000000ull);
|
|
}
|
|
PM128A XmmRegisters = &TestThreadStartupContext.Xmm0;
|
|
for (ULONG i = 0; i < 16; i++)
|
|
{
|
|
ok_eq_hex64(XmmRegisters[i].Low, 0x0000000000000000ull);
|
|
ok_eq_hex64(XmmRegisters[i].High, 0x0000000000000000ull);
|
|
}
|
|
for (ULONG i = 0; i < ARRAYSIZE(TestThreadStartupContext.VectorRegister); i++)
|
|
{
|
|
ok_eq_hex64(TestThreadStartupContext.VectorRegister[i].Low, 0xCCCCCCCCCCCCCCCCull);
|
|
ok_eq_hex64(TestThreadStartupContext.VectorRegister[i].High, 0xCCCCCCCCCCCCCCCCull);
|
|
}
|
|
|
|
/* Debug registers (reset to 0) */
|
|
ok_eq_hex64(TestThreadStartupContext.Dr0, 0x0000000000000000ull);
|
|
ok_eq_hex64(TestThreadStartupContext.Dr1, 0x0000000000000000ull);
|
|
ok_eq_hex64(TestThreadStartupContext.Dr2, 0x0000000000000000ull);
|
|
ok_eq_hex64(TestThreadStartupContext.Dr3, 0x0000000000000000ull);
|
|
ok_eq_hex64(TestThreadStartupContext.Dr6, 0x0000000000000000ull);
|
|
ok_eq_hex64(TestThreadStartupContext.Dr7, 0x0000000000000000ull);
|
|
|
|
#elif defined(_M_IX86)
|
|
|
|
/* Control */
|
|
ok_eq_hex(TestThreadStartupContext.Esp, Context.Esp);
|
|
ok_eq_hex(TestThreadStartupContext.EFlags, IsWow64 ? 0x00240ED7 : 0x003C4ED7);
|
|
|
|
/* Integer (copied) */
|
|
ok_eq_hex(TestThreadStartupContext.Eax, Context.Eax);
|
|
ok_eq_hex(TestThreadStartupContext.Ecx, Context.Ecx);
|
|
ok_eq_hex(TestThreadStartupContext.Edx, Context.Edx);
|
|
ok_eq_hex(TestThreadStartupContext.Ebx, Context.Ebx);
|
|
ok_eq_hex(TestThreadStartupContext.Ebp, Context.Ebp);
|
|
ok_eq_hex(TestThreadStartupContext.Esi, Context.Esi);
|
|
ok_eq_hex(TestThreadStartupContext.Edi, Context.Edi);
|
|
|
|
/* Segments (hardcoded, the upper 16 bits are left uninitialized by RtlCaptureContext) */
|
|
ok_eq_hex((USHORT)TestThreadStartupContext.SegCs, IsWow64 ? KGDT64_R3_CMCODE | RPL_MASK : KGDT_R3_CODE | RPL_MASK);
|
|
ok_eq_hex((USHORT)TestThreadStartupContext.SegDs, IsWow64 ? KGDT64_R3_DATA | RPL_MASK : KGDT_R3_DATA | RPL_MASK);
|
|
ok_eq_hex((USHORT)TestThreadStartupContext.SegEs, IsWow64 ? KGDT64_R3_DATA | RPL_MASK : KGDT_R3_DATA | RPL_MASK);
|
|
ok_eq_hex((USHORT)TestThreadStartupContext.SegFs, IsWow64 ? KGDT64_R3_CMTEB | RPL_MASK : KGDT_R3_TEB | RPL_MASK);
|
|
ok_eq_hex((USHORT)TestThreadStartupContext.SegGs, IsWow64 ? KGDT64_R3_DATA | RPL_MASK : 0x0000);
|
|
ok_eq_hex((USHORT)TestThreadStartupContext.SegSs, IsWow64 ? KGDT64_R3_DATA | RPL_MASK : KGDT_R3_DATA | RPL_MASK);
|
|
|
|
/* Floating point (hardcoded) */
|
|
ok_eq_hex(TestThreadStartupContext.FloatSave.ControlWord, IsWow64 ? 0x27F : 0xFFFF0A6A);
|
|
ok_eq_hex(TestThreadStartupContext.FloatSave.StatusWord, IsWow64 ? 0 : 0xFFFF2A2A);
|
|
ok_eq_hex(TestThreadStartupContext.FloatSave.TagWord, IsWow64 ? 0x0000FFFF : 0xFFFF0000);
|
|
ok_eq_hex(TestThreadStartupContext.FloatSave.ErrorOffset, IsWow64 ? 0 : 0xAAAAAAAA);
|
|
ok_eq_hex(TestThreadStartupContext.FloatSave.ErrorSelector, IsWow64 ? 0 : 0x02AAAAAA);
|
|
ok_eq_hex(TestThreadStartupContext.FloatSave.DataOffset, IsWow64 ? 0 : 0xAAAAAAAA);
|
|
ok_eq_hex(TestThreadStartupContext.FloatSave.DataSelector, IsWow64 ? 0 : 0xFFFFAAAA);
|
|
|
|
/* Debug registers (reset to 0) */
|
|
ok_eq_hex(TestThreadStartupContext.Dr0, 0x00000000);
|
|
ok_eq_hex(TestThreadStartupContext.Dr1, 0x00000000);
|
|
ok_eq_hex(TestThreadStartupContext.Dr2, 0x00000000);
|
|
ok_eq_hex(TestThreadStartupContext.Dr3, 0x00000000);
|
|
ok_eq_hex(TestThreadStartupContext.Dr6, 0x00000000);
|
|
ok_eq_hex(TestThreadStartupContext.Dr7, 0x00000000);
|
|
|
|
#else
|
|
|
|
#pragma message("Missing CONTEXT validation in NtCreateThread test")
|
|
ASSERT(FALSE);
|
|
|
|
#endif
|
|
|
|
#if defined(_M_AMD64) || defined(_M_IX86)
|
|
/* Test Eflags set to 0 */
|
|
Context.EFlags = 0;
|
|
TestThreadStartupContext.EFlags = 0xCCCCCCCC;
|
|
Status = NtCreateThread(&ThreadHandle,
|
|
THREAD_ALL_ACCESS,
|
|
NULL,
|
|
NtCurrentProcess(),
|
|
&ClientId,
|
|
&Context,
|
|
&InitialTeb,
|
|
TRUE);
|
|
ok_eq_hex(Status, STATUS_SUCCESS);
|
|
NtResumeThread(ThreadHandle, NULL);
|
|
WaitForSingleObject(ThreadHandle, INFINITE);
|
|
CloseHandle(ThreadHandle);
|
|
ok_eq_hex(TestThreadStartupContext.EFlags, 0x202);
|
|
#endif
|
|
|
|
#if !defined(_M_IX86) // FIXME: This crashes on x86
|
|
/* Test different InitialTeb values */
|
|
InitialTeb.PreviousStackBase = Stack;
|
|
InitialTeb.PreviousStackLimit = NULL;
|
|
Status = NtCreateThread(&ThreadHandle,
|
|
THREAD_ALL_ACCESS,
|
|
NULL,
|
|
NtCurrentProcess(),
|
|
&ClientId,
|
|
&Context,
|
|
&InitialTeb,
|
|
FALSE);
|
|
ok_eq_hex(Status, (GetNTVersion() >= _WIN32_WINNT_WIN10) ? STATUS_NOT_SUPPORTED : STATUS_SUCCESS);
|
|
|
|
InitialTeb.PreviousStackBase = NULL;
|
|
InitialTeb.PreviousStackLimit = Stack;
|
|
Status = NtCreateThread(&ThreadHandle,
|
|
THREAD_ALL_ACCESS,
|
|
NULL,
|
|
NtCurrentProcess(),
|
|
&ClientId,
|
|
&Context,
|
|
&InitialTeb,
|
|
FALSE);
|
|
ok_eq_hex(Status, (GetNTVersion() >= _WIN32_WINNT_WIN10) ? STATUS_NOT_SUPPORTED : STATUS_SUCCESS);
|
|
#endif
|
|
}
|