33 * LICENSE: See COPYING in the top level directory
44 * PURPOSE: Test for NtCreateThread
55 * PROGRAMMER: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6+ * PROGRAMMER: Timo Kreuzer <timo.kreuzer@reactos.org>
67 */
78
89#include "precomp.h"
910
11+ PVOID TestThreadProcPtr ;
12+ CONTEXT TestThreadStartupContext ;
13+ DECLSPEC_ALIGN (16 ) UCHAR TestThreadStartupStack [PAGE_SIZE ];
14+ BOOLEAN TestThreadFunctionCalled ;
15+ extern void ThreadStartupThunk (void * );
16+
17+ #define RPL_MASK 0x0003
18+ #define MODE_MASK 0x0001
19+ #define EFLAGS_INTERRUPT_MASK 0x200L
20+ #define KGDT_R3_CODE 0x0018
21+ #define KGDT_R3_DATA 0x0020
22+ #define KGDT_R3_TEB 0x0038
23+ #define KGDT64_R3_CMCODE 0x0020
24+ #define KGDT64_R3_DATA 0x0028
25+ #define KGDT64_R3_CODE 0x0030
26+ #define KGDT64_R3_CMTEB 0x0050
27+
28+ static
29+ VOID
30+ InitializeTestContext (PCONTEXT Context )
31+ {
32+ RtlFillMemory (Context , sizeof (* Context ), 0xAA );
33+
34+ Context -> ContextFlags = CONTEXT_ALL ;
35+
36+ #ifdef _M_AMD64
37+
38+ /* Control */
39+ Context -> Rsp = (ULONG64 )(TestThreadStartupStack + PAGE_SIZE - 16 );
40+ Context -> Rip = (ULONG64 )ThreadStartupThunk ;
41+
42+ /* Set Eflags. These get sanitized, but 0x100 (trap flag) makes it trap instantly. */
43+ Context -> EFlags = 0xFFFFFFFF ;
44+ Context -> EFlags &= ~0x100 ;
45+
46+ /* Integer (these are copied) */
47+ Context -> Rax = 0xF000000000000000 ;
48+ Context -> Rcx = 0xF000000000000001 ;
49+ Context -> Rdx = 0xF000000000000002 ;
50+ Context -> Rbx = 0xF000000000000003 ;
51+ Context -> Rbp = 0xF000000000000005 ;
52+ Context -> Rsi = 0xF000000000000006 ;
53+ Context -> Rdi = 0xF000000000000007 ;
54+ Context -> R8 = 0xF000000000000008 ;
55+ Context -> R9 = 0xF000000000000009 ;
56+ Context -> R10 = 0xF00000000000000A ;
57+ Context -> R11 = 0xF00000000000000B ;
58+ Context -> R12 = 0xF00000000000000C ;
59+ Context -> R13 = 0xF00000000000000D ;
60+ Context -> R14 = 0xF00000000000000E ;
61+ Context -> R15 = 0xF00000000000000F ;
62+
63+ #elif defined(_M_IX86 )
64+
65+ /* Control */
66+ Context -> Esp = (ULONG )(TestThreadStartupStack + PAGE_SIZE - 16 );
67+ Context -> Eip = (ULONG )ThreadStartupThunk ;
68+
69+ /* Set Eflags. These get sanitized, but 0x100 (trap flag) makes it trap instantly. */
70+ Context -> EFlags = 0xFFFFFFFF ;
71+ Context -> EFlags &= ~0x100 ; // Disable trap flag, because it would make the thread trap instantly
72+ Context -> EFlags &= ~0x00020000 ; // Disable V86 flag
73+
74+ /* Integer (these are copied) */
75+ Context -> Eax = 0xF0000000 ;
76+ Context -> Ecx = 0xF0000001 ;
77+ Context -> Edx = 0xF0000002 ;
78+ Context -> Ebx = 0xF0000003 ;
79+ Context -> Ebp = 0xF0000005 ;
80+ Context -> Esi = 0xF0000006 ;
81+ Context -> Edi = 0xF0000007 ;
82+
83+ /* FIXME: Initialize segments to prevent ReactOS from crashing in the kernel */
84+ Context -> SegCs = KGDT_R3_CODE | RPL_MASK ;
85+ Context -> SegSs = KGDT_R3_DATA | RPL_MASK ;
86+ Context -> SegDs = KGDT_R3_DATA | RPL_MASK ;
87+ Context -> SegEs = KGDT_R3_DATA | RPL_MASK ;
88+ Context -> SegFs = KGDT_R3_TEB | RPL_MASK ;
89+ Context -> SegGs = 0 ;
90+
91+ #else
92+
93+ #pragma message("Missing CONTEXT setup in NtCreateThread test")
94+ ASSERT (FALSE);
95+
96+ #endif
97+ }
98+
99+ VOID
100+ NTAPI
101+ TestThreadProc (IN PVOID StartContext )
102+ {
103+ TestThreadFunctionCalled = TRUE;
104+
105+ #if defined(_M_IX86 ) || defined(_M_AMD64 )
106+ CONTEXT Context ;
107+
108+ /* Get the debug registers and floating point */
109+ Context .ContextFlags = CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT ;
110+ GetThreadContext (NtCurrentThread (), & Context );
111+ TestThreadStartupContext .Dr0 = Context .Dr0 ;
112+ TestThreadStartupContext .Dr1 = Context .Dr1 ;
113+ TestThreadStartupContext .Dr2 = Context .Dr2 ;
114+ TestThreadStartupContext .Dr3 = Context .Dr3 ;
115+ TestThreadStartupContext .Dr6 = Context .Dr6 ;
116+ TestThreadStartupContext .Dr7 = Context .Dr7 ;
117+ #if defined(_M_IX86 )
118+ TestThreadStartupContext .FloatSave = Context .FloatSave ;
119+ #endif
120+ #endif
121+
122+ /* Terminate current thread */
123+ NtTerminateThread (NtCurrentThread (), STATUS_SUCCESS );
124+ }
125+
10126START_TEST (NtCreateThread )
11127{
12128 NTSTATUS Status ;
13129 INITIAL_TEB InitialTeb ;
14130 HANDLE ThreadHandle ;
15131 OBJECT_ATTRIBUTES Attributes ;
132+ DECLSPEC_ALIGN (16 ) ULONG_PTR Stack [128 ];
133+ PULONG_PTR StackPtr = & Stack [ARRAYSIZE (Stack ) - 2 ];
134+ CONTEXT Context ;
135+ CLIENT_ID ClientId ;
136+
137+ BOOL IsWow64 = FALSE;
138+ IsWow64Process (GetCurrentProcess (), & IsWow64 );
16139
17140 InitializeObjectAttributes (& Attributes , NULL , 0 , NULL , NULL );
18141 ZeroMemory (& InitialTeb , sizeof (INITIAL_TEB ));
@@ -27,4 +150,196 @@ START_TEST(NtCreateThread)
27150 FALSE);
28151
29152 ok_hex (Status , STATUS_ACCESS_VIOLATION );
153+
154+ InitialTeb .PreviousStackBase = NULL ;
155+ InitialTeb .PreviousStackLimit = NULL ;
156+ InitialTeb .StackBase = StackPtr ;
157+ InitialTeb .StackLimit = Stack ;
158+ InitialTeb .AllocatedStackBase = Stack ;
159+
160+ TestThreadProcPtr = TestThreadProc ;
161+
162+ RtlFillMemory (& TestThreadStartupContext , sizeof (TestThreadStartupContext ), 0xCC );
163+ InitializeTestContext (& Context );
164+
165+ Status = NtCreateThread (& ThreadHandle ,
166+ THREAD_ALL_ACCESS ,
167+ NULL ,
168+ NtCurrentProcess (),
169+ & ClientId ,
170+ & Context ,
171+ & InitialTeb ,
172+ TRUE);
173+ ok_eq_hex (Status , STATUS_SUCCESS );
174+
175+ NtResumeThread (ThreadHandle , NULL );
176+ WaitForSingleObject (ThreadHandle , INFINITE );
177+ CloseHandle (ThreadHandle );
178+
179+ ok_eq_bool (TestThreadFunctionCalled , TRUE);
180+ TestThreadFunctionCalled = FALSE;
181+
182+ #ifdef _M_AMD64
183+
184+ /* Control */
185+ ok_eq_hex64 (TestThreadStartupContext .Rsp , Context .Rsp - 0x28 );
186+ ok_eq_hex64 (TestThreadStartupContext .SegCs , 0x0033 );
187+ ok_eq_hex64 (TestThreadStartupContext .EFlags , 0x200ED7 );
188+ ok_eq_hex (TestThreadStartupContext .SegSs , 0x0002B );
189+
190+ /* Integer (copied) */
191+ ok_eq_hex64 (TestThreadStartupContext .Rax , Context .Rax );
192+ ok_eq_hex64 (TestThreadStartupContext .Rcx , Context .Rcx );
193+ ok_eq_hex64 (TestThreadStartupContext .Rdx , Context .Rdx );
194+ ok_eq_hex64 (TestThreadStartupContext .Rbx , Context .Rbx );
195+ ok_eq_hex64 (TestThreadStartupContext .Rbp , (GetNTVersion () >= _WIN32_WINNT_WIN10 ) ? Context .Rbp : 0 );
196+ ok_eq_hex64 (TestThreadStartupContext .Rsi , Context .Rsi );
197+ ok_eq_hex64 (TestThreadStartupContext .Rdi , Context .Rdi );
198+ ok_eq_hex64 (TestThreadStartupContext .R8 , Context .R8 );
199+ ok_eq_hex64 (TestThreadStartupContext .R9 , Context .R9 );
200+ ok_eq_hex64 (TestThreadStartupContext .R10 , Context .R10 );
201+ ok_eq_hex64 (TestThreadStartupContext .R11 , Context .R11 );
202+ ok_eq_hex64 (TestThreadStartupContext .R12 , Context .R12 );
203+ ok_eq_hex64 (TestThreadStartupContext .R13 , Context .R13 );
204+ ok_eq_hex64 (TestThreadStartupContext .R14 , Context .R14 );
205+ ok_eq_hex64 (TestThreadStartupContext .R15 , Context .R15 );
206+
207+ /* Segments (hardcoded) */
208+ ok_eq_hex (TestThreadStartupContext .SegDs , KGDT64_R3_DATA | RPL_MASK );
209+ ok_eq_hex (TestThreadStartupContext .SegEs , KGDT64_R3_DATA | RPL_MASK );
210+ ok_eq_hex (TestThreadStartupContext .SegFs , KGDT64_R3_CMTEB | RPL_MASK );
211+ ok_eq_hex (TestThreadStartupContext .SegGs , KGDT64_R3_DATA | RPL_MASK );
212+
213+ /* Floating point (hardcoded) */
214+ ok_eq_hex64 (TestThreadStartupContext .MxCsr , INITIAL_MXCSR );
215+ ok_eq_hex (TestThreadStartupContext .FltSave .ControlWord , INITIAL_FPCSR );
216+ ok_eq_hex (TestThreadStartupContext .FltSave .StatusWord , 0x0000 );
217+ ok_eq_hex (TestThreadStartupContext .FltSave .TagWord , 0x00 );
218+ ok_eq_hex (TestThreadStartupContext .FltSave .Reserved1 , 0x00 );
219+ ok_eq_hex (TestThreadStartupContext .FltSave .ErrorOpcode , 0x0000 );
220+ ok_eq_hex (TestThreadStartupContext .FltSave .ErrorOffset , 0x00000000 );
221+ ok_eq_hex (TestThreadStartupContext .FltSave .ErrorSelector , 0x0000 );
222+ ok_eq_hex (TestThreadStartupContext .FltSave .Reserved2 , 0x0000 );
223+ ok_eq_hex (TestThreadStartupContext .FltSave .DataOffset , 0x00000000 );
224+ ok_eq_hex (TestThreadStartupContext .FltSave .DataSelector , 0x0000 );
225+ ok_eq_hex (TestThreadStartupContext .FltSave .Reserved3 , 0x0000 );
226+ ok_eq_hex (TestThreadStartupContext .FltSave .MxCsr , INITIAL_MXCSR );
227+ ok_eq_hex (TestThreadStartupContext .FltSave .MxCsr_Mask , 0x0002FFFF );
228+ for (ULONG i = 0 ; i < ARRAYSIZE (TestThreadStartupContext .FltSave .FloatRegisters ); i ++ )
229+ {
230+ ok_eq_hex64 (TestThreadStartupContext .FltSave .FloatRegisters [i ].Low , 0x0000000000000000ull );
231+ ok_eq_hex64 (TestThreadStartupContext .FltSave .FloatRegisters [i ].High , 0x0000000000000000ull );
232+ }
233+ PM128A XmmRegisters = & TestThreadStartupContext .Xmm0 ;
234+ for (ULONG i = 0 ; i < 16 ; i ++ )
235+ {
236+ ok_eq_hex64 (XmmRegisters [i ].Low , 0x0000000000000000ull );
237+ ok_eq_hex64 (XmmRegisters [i ].High , 0x0000000000000000ull );
238+ }
239+ for (ULONG i = 0 ; i < ARRAYSIZE (TestThreadStartupContext .VectorRegister ); i ++ )
240+ {
241+ ok_eq_hex64 (TestThreadStartupContext .VectorRegister [i ].Low , 0xCCCCCCCCCCCCCCCCull );
242+ ok_eq_hex64 (TestThreadStartupContext .VectorRegister [i ].High , 0xCCCCCCCCCCCCCCCCull );
243+ }
244+
245+ /* Debug registers (reset to 0) */
246+ ok_eq_hex64 (TestThreadStartupContext .Dr0 , 0x0000000000000000ull );
247+ ok_eq_hex64 (TestThreadStartupContext .Dr1 , 0x0000000000000000ull );
248+ ok_eq_hex64 (TestThreadStartupContext .Dr2 , 0x0000000000000000ull );
249+ ok_eq_hex64 (TestThreadStartupContext .Dr3 , 0x0000000000000000ull );
250+ ok_eq_hex64 (TestThreadStartupContext .Dr6 , 0x0000000000000000ull );
251+ ok_eq_hex64 (TestThreadStartupContext .Dr7 , 0x0000000000000000ull );
252+
253+ #elif defined(_M_IX86 )
254+
255+ /* Control */
256+ ok_eq_hex (TestThreadStartupContext .Esp , Context .Esp );
257+ ok_eq_hex (TestThreadStartupContext .EFlags , IsWow64 ? 0x00240ED7 : 0x003C4ED7 );
258+
259+ /* Integer (copied) */
260+ ok_eq_hex (TestThreadStartupContext .Eax , Context .Eax );
261+ ok_eq_hex (TestThreadStartupContext .Ecx , Context .Ecx );
262+ ok_eq_hex (TestThreadStartupContext .Edx , Context .Edx );
263+ ok_eq_hex (TestThreadStartupContext .Ebx , Context .Ebx );
264+ ok_eq_hex (TestThreadStartupContext .Ebp , Context .Ebp );
265+ ok_eq_hex (TestThreadStartupContext .Esi , Context .Esi );
266+ ok_eq_hex (TestThreadStartupContext .Edi , Context .Edi );
267+
268+ /* Segments (hardcoded, the upper 16 bits are left uninitialized by RtlCaptureContext) */
269+ ok_eq_hex ((USHORT )TestThreadStartupContext .SegCs , IsWow64 ? KGDT64_R3_CMCODE | RPL_MASK : KGDT_R3_CODE | RPL_MASK );
270+ ok_eq_hex ((USHORT )TestThreadStartupContext .SegDs , IsWow64 ? KGDT64_R3_DATA | RPL_MASK : KGDT_R3_DATA | RPL_MASK );
271+ ok_eq_hex ((USHORT )TestThreadStartupContext .SegEs , IsWow64 ? KGDT64_R3_DATA | RPL_MASK : KGDT_R3_DATA | RPL_MASK );
272+ ok_eq_hex ((USHORT )TestThreadStartupContext .SegFs , IsWow64 ? KGDT64_R3_CMTEB | RPL_MASK : KGDT_R3_TEB | RPL_MASK );
273+ ok_eq_hex ((USHORT )TestThreadStartupContext .SegGs , IsWow64 ? KGDT64_R3_DATA | RPL_MASK : 0x0000 );
274+ ok_eq_hex ((USHORT )TestThreadStartupContext .SegSs , IsWow64 ? KGDT64_R3_DATA | RPL_MASK : KGDT_R3_DATA | RPL_MASK );
275+
276+ /* Floating point (hardcoded) */
277+ ok_eq_hex (TestThreadStartupContext .FloatSave .ControlWord , IsWow64 ? 0x27F : 0xFFFF0A6A );
278+ ok_eq_hex (TestThreadStartupContext .FloatSave .StatusWord , IsWow64 ? 0 : 0xFFFF2A2A );
279+ ok_eq_hex (TestThreadStartupContext .FloatSave .TagWord , IsWow64 ? 0x0000FFFF : 0xFFFF0000 );
280+ ok_eq_hex (TestThreadStartupContext .FloatSave .ErrorOffset , IsWow64 ? 0 : 0xAAAAAAAA );
281+ ok_eq_hex (TestThreadStartupContext .FloatSave .ErrorSelector , IsWow64 ? 0 : 0x02AAAAAA );
282+ ok_eq_hex (TestThreadStartupContext .FloatSave .DataOffset , IsWow64 ? 0 : 0xAAAAAAAA );
283+ ok_eq_hex (TestThreadStartupContext .FloatSave .DataSelector , IsWow64 ? 0 : 0xFFFFAAAA );
284+
285+ /* Debug registers (reset to 0) */
286+ ok_eq_hex (TestThreadStartupContext .Dr0 , 0x00000000 );
287+ ok_eq_hex (TestThreadStartupContext .Dr1 , 0x00000000 );
288+ ok_eq_hex (TestThreadStartupContext .Dr2 , 0x00000000 );
289+ ok_eq_hex (TestThreadStartupContext .Dr3 , 0x00000000 );
290+ ok_eq_hex (TestThreadStartupContext .Dr6 , 0x00000000 );
291+ ok_eq_hex (TestThreadStartupContext .Dr7 , 0x00000000 );
292+
293+ #else
294+
295+ #pragma message("Missing CONTEXT validation in NtCreateThread test")
296+ ASSERT (FALSE);
297+
298+ #endif
299+
300+ #if defined(_M_AMD64 ) || defined(_M_IX86 )
301+ /* Test Eflags set to 0 */
302+ Context .EFlags = 0 ;
303+ TestThreadStartupContext .EFlags = 0xCCCCCCCC ;
304+ Status = NtCreateThread (& ThreadHandle ,
305+ THREAD_ALL_ACCESS ,
306+ NULL ,
307+ NtCurrentProcess (),
308+ & ClientId ,
309+ & Context ,
310+ & InitialTeb ,
311+ TRUE);
312+ ok_eq_hex (Status , STATUS_SUCCESS );
313+ NtResumeThread (ThreadHandle , NULL );
314+ WaitForSingleObject (ThreadHandle , INFINITE );
315+ CloseHandle (ThreadHandle );
316+ ok_eq_hex (TestThreadStartupContext .EFlags , 0x202 );
317+ #endif
318+
319+ #if !defined(_M_IX86 ) // FIXME: This crashes on x86
320+ /* Test different InitialTeb values */
321+ InitialTeb .PreviousStackBase = Stack ;
322+ InitialTeb .PreviousStackLimit = NULL ;
323+ Status = NtCreateThread (& ThreadHandle ,
324+ THREAD_ALL_ACCESS ,
325+ NULL ,
326+ NtCurrentProcess (),
327+ & ClientId ,
328+ & Context ,
329+ & InitialTeb ,
330+ FALSE);
331+ ok_eq_hex (Status , (GetNTVersion () >= _WIN32_WINNT_WIN10 ) ? STATUS_NOT_SUPPORTED : STATUS_SUCCESS );
332+
333+ InitialTeb .PreviousStackBase = NULL ;
334+ InitialTeb .PreviousStackLimit = Stack ;
335+ Status = NtCreateThread (& ThreadHandle ,
336+ THREAD_ALL_ACCESS ,
337+ NULL ,
338+ NtCurrentProcess (),
339+ & ClientId ,
340+ & Context ,
341+ & InitialTeb ,
342+ FALSE);
343+ ok_eq_hex (Status , (GetNTVersion () >= _WIN32_WINNT_WIN10 ) ? STATUS_NOT_SUPPORTED : STATUS_SUCCESS );
344+ #endif
30345}
0 commit comments