2 * Unit test suite for ntdll thread functions
4 * Copyright 2021 Paul Gofman for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "ntdll_test.h"
24 static NTSTATUS (WINAPI
*pNtCreateThreadEx
)( HANDLE
*, ACCESS_MASK
, OBJECT_ATTRIBUTES
*,
25 HANDLE
, PRTL_THREAD_START_ROUTINE
, void *,
26 ULONG
, ULONG_PTR
, SIZE_T
, SIZE_T
, PS_ATTRIBUTE_LIST
* );
28 static void init_function_pointers(void)
30 HMODULE hntdll
= GetModuleHandleA( "ntdll.dll" );
31 #define GET_FUNC(name) p##name = (void *)GetProcAddress( hntdll, #name );
32 GET_FUNC( NtCreateThreadEx
);
36 static void CALLBACK
test_NtCreateThreadEx_proc(void *param
)
40 static void test_dbg_hidden_thread_creation(void)
42 RTL_USER_PROCESS_PARAMETERS
*params
;
43 PS_CREATE_INFO create_info
;
44 PS_ATTRIBUTE_LIST ps_attr
;
45 WCHAR path
[MAX_PATH
+ 4];
46 HANDLE process
, thread
;
47 UNICODE_STRING imageW
;
51 if (!pNtCreateThreadEx
)
53 win_skip( "NtCreateThreadEx is not available.\n" );
57 status
= pNtCreateThreadEx( &thread
, THREAD_ALL_ACCESS
, NULL
, GetCurrentProcess(), test_NtCreateThreadEx_proc
,
58 NULL
, THREAD_CREATE_FLAGS_CREATE_SUSPENDED
, 0, 0, 0, NULL
);
59 ok( status
== STATUS_SUCCESS
, "Got unexpected status %#lx.\n", status
);
62 status
= NtQueryInformationThread( thread
, ThreadHideFromDebugger
, &dbg_hidden
, sizeof(dbg_hidden
), NULL
);
63 ok( status
== STATUS_SUCCESS
, "Got unexpected status %#lx.\n", status
);
64 ok( !dbg_hidden
, "Got unexpected dbg_hidden %#x.\n", dbg_hidden
);
66 status
= NtResumeThread( thread
, NULL
);
67 ok( status
== STATUS_SUCCESS
, "Got unexpected status %#lx.\n", status
);
68 WaitForSingleObject( thread
, INFINITE
);
69 CloseHandle( thread
);
71 status
= pNtCreateThreadEx( &thread
, THREAD_ALL_ACCESS
, NULL
, GetCurrentProcess(), test_NtCreateThreadEx_proc
,
72 NULL
, THREAD_CREATE_FLAGS_CREATE_SUSPENDED
| THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER
,
74 ok( status
== STATUS_SUCCESS
, "Got unexpected status %#lx.\n", status
);
77 status
= NtQueryInformationThread( thread
, ThreadHideFromDebugger
, &dbg_hidden
, sizeof(dbg_hidden
), NULL
);
78 ok( status
== STATUS_SUCCESS
, "Got unexpected status %#lx.\n", status
);
79 ok( dbg_hidden
== 1, "Got unexpected dbg_hidden %#x.\n", dbg_hidden
);
81 status
= NtResumeThread( thread
, NULL
);
82 ok( status
== STATUS_SUCCESS
, "Got unexpected status %#lx.\n", status
);
83 WaitForSingleObject( thread
, INFINITE
);
84 CloseHandle( thread
);
86 lstrcpyW( path
, L
"\\??\\" );
87 GetModuleFileNameW( NULL
, path
+ 4, MAX_PATH
);
89 RtlInitUnicodeString( &imageW
, path
);
91 memset( &ps_attr
, 0, sizeof(ps_attr
) );
92 ps_attr
.Attributes
[0].Attribute
= PS_ATTRIBUTE_IMAGE_NAME
;
93 ps_attr
.Attributes
[0].Size
= lstrlenW(path
) * sizeof(WCHAR
);
94 ps_attr
.Attributes
[0].ValuePtr
= path
;
95 ps_attr
.TotalLength
= sizeof(ps_attr
);
97 status
= RtlCreateProcessParametersEx( ¶ms
, &imageW
, NULL
, NULL
,
98 NULL
, NULL
, NULL
, NULL
,
99 NULL
, NULL
, PROCESS_PARAMS_FLAG_NORMALIZED
);
100 ok( status
== STATUS_SUCCESS
, "Got unexpected status %#lx.\n", status
);
102 /* NtCreateUserProcess() may return STATUS_INVALID_PARAMETER with some uninitialized data in create_info. */
103 memset( &create_info
, 0, sizeof(create_info
) );
104 create_info
.Size
= sizeof(create_info
);
106 status
= NtCreateUserProcess( &process
, &thread
, PROCESS_ALL_ACCESS
, THREAD_ALL_ACCESS
,
107 NULL
, NULL
, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED
108 | THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER
, params
,
109 &create_info
, &ps_attr
);
110 ok( status
== STATUS_INVALID_PARAMETER
, "Got unexpected status %#lx.\n", status
);
111 status
= NtCreateUserProcess( &process
, &thread
, PROCESS_ALL_ACCESS
, THREAD_ALL_ACCESS
,
112 NULL
, NULL
, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED
, params
,
113 &create_info
, &ps_attr
);
114 ok( status
== STATUS_SUCCESS
, "Got unexpected status %#lx.\n", status
);
115 status
= NtTerminateProcess( process
, 0 );
116 ok( status
== STATUS_SUCCESS
, "Got unexpected status %#lx.\n", status
);
117 CloseHandle( process
);
118 CloseHandle( thread
);
121 struct unique_teb_thread_args
124 HANDLE running_event
;
128 static void CALLBACK
test_unique_teb_proc(void *param
)
130 struct unique_teb_thread_args
*args
= param
;
131 args
->teb
= NtCurrentTeb();
132 SetEvent( args
->running_event
);
133 WaitForSingleObject( args
->quit_event
, INFINITE
);
136 static void test_unique_teb(void)
138 HANDLE threads
[2], running_events
[2];
139 struct unique_teb_thread_args args1
, args2
;
142 if (!pNtCreateThreadEx
)
144 win_skip( "NtCreateThreadEx is not available.\n" );
148 args1
.running_event
= running_events
[0] = CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
149 ok( args1
.running_event
!= NULL
, "CreateEventW failed %lu.\n", GetLastError() );
151 args2
.running_event
= running_events
[1] = CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
152 ok( args2
.running_event
!= NULL
, "CreateEventW failed %lu.\n", GetLastError() );
154 args1
.quit_event
= args2
.quit_event
= CreateEventW( NULL
, TRUE
, FALSE
, NULL
);
155 ok( args1
.quit_event
!= NULL
, "CreateEventW failed %lu.\n", GetLastError() );
157 status
= pNtCreateThreadEx( &threads
[0], THREAD_ALL_ACCESS
, NULL
, GetCurrentProcess(), test_unique_teb_proc
,
158 &args1
, 0, 0, 0, 0, NULL
);
159 ok( status
== STATUS_SUCCESS
, "Got unexpected status %#lx.\n", status
);
161 status
= pNtCreateThreadEx( &threads
[1], THREAD_ALL_ACCESS
, NULL
, GetCurrentProcess(), test_unique_teb_proc
,
162 &args2
, 0, 0, 0, 0, NULL
);
163 ok( status
== STATUS_SUCCESS
, "Got unexpected status %#lx.\n", status
);
165 WaitForMultipleObjects( 2, running_events
, TRUE
, INFINITE
);
166 SetEvent( args1
.quit_event
);
168 WaitForMultipleObjects( 2, threads
, TRUE
, INFINITE
);
169 CloseHandle( threads
[0] );
170 CloseHandle( threads
[1] );
171 CloseHandle( args1
.running_event
);
172 CloseHandle( args2
.running_event
);
173 CloseHandle( args1
.quit_event
);
175 ok( NtCurrentTeb() != args1
.teb
, "Multiple threads have TEB %p.\n", args1
.teb
);
176 ok( NtCurrentTeb() != args2
.teb
, "Multiple threads have TEB %p.\n", args2
.teb
);
177 ok( args1
.teb
!= args2
.teb
, "Multiple threads have TEB %p.\n", args1
.teb
);
182 init_function_pointers();
184 test_dbg_hidden_thread_creation();