mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2024-11-21 17:09:06 -07:00
Merge branch 'ntdll_process_tls_info' into 'master'
ntdll: Implement NtSetInformationProcess( ProcessTlsInformation ) and use that in loader. See merge request wine/wine!6549
This commit is contained in:
commit
e6ab7187f3
9 changed files with 600 additions and 51 deletions
|
@ -1708,7 +1708,10 @@ static void test_tls_links(void)
|
||||||
TEB *teb = NtCurrentTeb(), *thread_teb;
|
TEB *teb = NtCurrentTeb(), *thread_teb;
|
||||||
THREAD_BASIC_INFORMATION tbi;
|
THREAD_BASIC_INFORMATION tbi;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
ULONG i, count;
|
||||||
HANDLE thread;
|
HANDLE thread;
|
||||||
|
SIZE_T size;
|
||||||
|
void **ptr;
|
||||||
|
|
||||||
ok(!!teb->ThreadLocalStoragePointer, "got NULL.\n");
|
ok(!!teb->ThreadLocalStoragePointer, "got NULL.\n");
|
||||||
|
|
||||||
|
@ -1728,6 +1731,26 @@ static void test_tls_links(void)
|
||||||
ResumeThread(thread);
|
ResumeThread(thread);
|
||||||
WaitForSingleObject(test_tls_links_started, INFINITE);
|
WaitForSingleObject(test_tls_links_started, INFINITE);
|
||||||
|
|
||||||
|
if (!is_old_loader_struct())
|
||||||
|
{
|
||||||
|
ptr = teb->ThreadLocalStoragePointer;
|
||||||
|
count = (ULONG_PTR)ptr[-2];
|
||||||
|
size = HeapSize(GetProcessHeap(), 0, ptr - 2);
|
||||||
|
ok(size == (count + 2) * sizeof(void *), "got count %lu, size %Iu.\n", count, size);
|
||||||
|
|
||||||
|
for (i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
if (!ptr[i]) continue;
|
||||||
|
size = HeapSize(GetProcessHeap(), 0, (void **)ptr[i] - 2);
|
||||||
|
ok(size && size < 100000, "got %Iu.\n", size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = thread_teb->ThreadLocalStoragePointer;
|
||||||
|
count = (ULONG_PTR)ptr[-2];
|
||||||
|
size = HeapSize(GetProcessHeap(), 0, ptr - 2);
|
||||||
|
ok(size == (count + 2) * sizeof(void *), "got count %lu, size %Iu.\n", count, size);
|
||||||
|
}
|
||||||
|
|
||||||
ok(!!thread_teb->ThreadLocalStoragePointer, "got NULL.\n");
|
ok(!!thread_teb->ThreadLocalStoragePointer, "got NULL.\n");
|
||||||
ok(!teb->TlsLinks.Flink, "got %p.\n", teb->TlsLinks.Flink);
|
ok(!teb->TlsLinks.Flink, "got %p.\n", teb->TlsLinks.Flink);
|
||||||
ok(!teb->TlsLinks.Blink, "got %p.\n", teb->TlsLinks.Blink);
|
ok(!teb->TlsLinks.Blink, "got %p.\n", teb->TlsLinks.Blink);
|
||||||
|
|
|
@ -142,6 +142,7 @@ typedef struct _wine_modref
|
||||||
|
|
||||||
static UINT tls_module_count = 32; /* number of modules with TLS directory */
|
static UINT tls_module_count = 32; /* number of modules with TLS directory */
|
||||||
static IMAGE_TLS_DIRECTORY *tls_dirs; /* array of TLS directories */
|
static IMAGE_TLS_DIRECTORY *tls_dirs; /* array of TLS directories */
|
||||||
|
static ULONG tls_thread_count; /* number of threads for which ThreadLocalStoragePointer is allocated in TEB. */
|
||||||
|
|
||||||
static RTL_CRITICAL_SECTION loader_section;
|
static RTL_CRITICAL_SECTION loader_section;
|
||||||
static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
|
static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
|
||||||
|
@ -1332,6 +1333,36 @@ static BOOL is_dll_native_subsystem( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_NT_H
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* alloc_tls_memory
|
||||||
|
*
|
||||||
|
* Allocate memory for TLS vector or index with an extra data.
|
||||||
|
*/
|
||||||
|
static void *alloc_tls_memory( BOOL vector, ULONG_PTR size )
|
||||||
|
{
|
||||||
|
ULONG_PTR *ptr;
|
||||||
|
|
||||||
|
if (!(ptr = RtlAllocateHeap( GetProcessHeap(), vector ? HEAP_ZERO_MEMORY : 0, size + sizeof(void *) * 2 ))) return NULL;
|
||||||
|
ptr += 2;
|
||||||
|
if (vector) ptr[-2] = size / sizeof(void *);
|
||||||
|
else ptr[-2] = ptr[-1] = 0;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* free_tls_memory
|
||||||
|
*
|
||||||
|
* Free TLS vector or index memory.
|
||||||
|
*/
|
||||||
|
static void free_tls_memory( void *ptr )
|
||||||
|
{
|
||||||
|
if (!ptr) return;
|
||||||
|
RtlFreeHeap( GetProcessHeap(), 0, (void **)ptr - 2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* alloc_tls_slot
|
* alloc_tls_slot
|
||||||
*
|
*
|
||||||
|
@ -1341,10 +1372,10 @@ static BOOL is_dll_native_subsystem( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_NT_H
|
||||||
static BOOL alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
|
static BOOL alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
|
||||||
{
|
{
|
||||||
const IMAGE_TLS_DIRECTORY *dir;
|
const IMAGE_TLS_DIRECTORY *dir;
|
||||||
ULONG i, size;
|
ULONG i, j, size;
|
||||||
void *new_ptr;
|
void *new_ptr;
|
||||||
UINT old_module_count = tls_module_count;
|
UINT old_module_count = tls_module_count;
|
||||||
HANDLE thread = NULL, next;
|
PROCESS_TLS_INFORMATION *t;
|
||||||
|
|
||||||
if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size )))
|
if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size )))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -1373,57 +1404,66 @@ static BOOL alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
|
||||||
tls_dirs = new_ptr;
|
tls_dirs = new_ptr;
|
||||||
tls_module_count = new_count;
|
tls_module_count = new_count;
|
||||||
}
|
}
|
||||||
|
*(DWORD *)dir->AddressOfIndex = i;
|
||||||
|
tls_dirs[i] = *dir;
|
||||||
|
|
||||||
/* allocate the data block in all running threads */
|
if (!tls_thread_count) return TRUE;
|
||||||
while (!NtGetNextThread( GetCurrentProcess(), thread, THREAD_QUERY_LIMITED_INFORMATION, 0, 0, &next ))
|
t = RtlAllocateHeap( GetProcessHeap(), 0, offsetof( PROCESS_TLS_INFORMATION, ThreadData[tls_thread_count] ));
|
||||||
|
if (!t) return FALSE;
|
||||||
|
|
||||||
|
t->Flags = 0;
|
||||||
|
t->ThreadDataCount = tls_thread_count;
|
||||||
|
if (old_module_count < tls_module_count)
|
||||||
{
|
{
|
||||||
THREAD_BASIC_INFORMATION tbi;
|
t->OperationType = ProcessTlsReplaceVector;
|
||||||
TEB *teb;
|
t->TlsVectorLength = old_module_count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t->OperationType = ProcessTlsReplaceIndex;
|
||||||
|
t->TlsIndex = i;
|
||||||
|
}
|
||||||
|
for (j = 0; j < tls_thread_count; ++j)
|
||||||
|
{
|
||||||
|
void **vector;
|
||||||
|
|
||||||
if (thread) NtClose( thread );
|
t->ThreadData[j].Flags = 0;
|
||||||
thread = next;
|
|
||||||
if (NtQueryInformationThread( thread, ThreadBasicInformation, &tbi, sizeof(tbi), NULL ) || !tbi.TebBaseAddress)
|
|
||||||
{
|
|
||||||
ERR( "NtQueryInformationThread failed.\n" );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
teb = tbi.TebBaseAddress;
|
|
||||||
if (!teb->ThreadLocalStoragePointer)
|
|
||||||
{
|
|
||||||
/* Thread is not initialized by loader yet or already teared down. */
|
|
||||||
TRACE( "thread %04lx NULL tls block.\n", HandleToULong(tbi.ClientId.UniqueThread) );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (old_module_count < tls_module_count)
|
if (!(new_ptr = alloc_tls_memory( FALSE, size + dir->SizeOfZeroFill ))) return FALSE;
|
||||||
{
|
|
||||||
void **old = teb->ThreadLocalStoragePointer;
|
|
||||||
void **new = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, tls_module_count * sizeof(*new));
|
|
||||||
|
|
||||||
if (!new) return FALSE;
|
|
||||||
if (old) memcpy( new, old, old_module_count * sizeof(*new) );
|
|
||||||
teb->ThreadLocalStoragePointer = new;
|
|
||||||
#ifdef __x86_64__ /* macOS-specific hack */
|
|
||||||
if (teb->Instrumentation[0]) ((TEB *)teb->Instrumentation[0])->ThreadLocalStoragePointer = new;
|
|
||||||
#endif
|
|
||||||
TRACE( "thread %04lx tls block %p -> %p\n", HandleToULong(teb->ClientId.UniqueThread), old, new );
|
|
||||||
/* FIXME: can't free old block here, should be freed at thread exit */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(new_ptr = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill ))) return -1;
|
|
||||||
memcpy( new_ptr, (void *)dir->StartAddressOfRawData, size );
|
memcpy( new_ptr, (void *)dir->StartAddressOfRawData, size );
|
||||||
memset( (char *)new_ptr + size, 0, dir->SizeOfZeroFill );
|
memset( (char *)new_ptr + size, 0, dir->SizeOfZeroFill );
|
||||||
|
|
||||||
TRACE( "thread %04lx slot %lu: %lu/%lu bytes at %p\n",
|
if (t->OperationType == ProcessTlsReplaceVector)
|
||||||
HandleToULong(teb->ClientId.UniqueThread), i, size, dir->SizeOfZeroFill, new_ptr );
|
{
|
||||||
|
vector = alloc_tls_memory( TRUE, tls_module_count * sizeof(*vector) );
|
||||||
RtlFreeHeap( GetProcessHeap(), 0,
|
if (!vector) return FALSE;
|
||||||
InterlockedExchangePointer( (void **)teb->ThreadLocalStoragePointer + i, new_ptr ));
|
t->ThreadData[j].TlsVector = vector;
|
||||||
|
vector[i] = new_ptr;
|
||||||
|
}
|
||||||
|
else t->ThreadData[j].TlsModulePointer = new_ptr;
|
||||||
|
}
|
||||||
|
if (NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, t,
|
||||||
|
offsetof(PROCESS_TLS_INFORMATION, ThreadData[t->ThreadDataCount])))
|
||||||
|
{
|
||||||
|
ERR( "ProcessTlsInformation failed.\n" );
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (thread) NtClose( thread );
|
|
||||||
|
|
||||||
*(DWORD *)dir->AddressOfIndex = i;
|
for (j = 0; j < tls_thread_count; ++j)
|
||||||
tls_dirs[i] = *dir;
|
{
|
||||||
|
if (!(t->ThreadData[j].Flags & THREAD_TLS_INFORMATION_ASSIGNED) && t->OperationType == ProcessTlsReplaceVector)
|
||||||
|
{
|
||||||
|
/* There could be fewer active threads than we counted here due to force terminated threads, first
|
||||||
|
* free extra TLS directory data set in the new TLS vector. */
|
||||||
|
free_tls_memory( ((void **)t->ThreadData[j].TlsVector)[i] );
|
||||||
|
}
|
||||||
|
if (!(t->ThreadData[j].Flags & THREAD_TLS_INFORMATION_ASSIGNED) || t->OperationType == ProcessTlsReplaceIndex)
|
||||||
|
{
|
||||||
|
/* FIXME: can't free old Tls vector here, should be freed at thread exit. */
|
||||||
|
free_tls_memory( t->ThreadData[j].TlsVector );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RtlFreeHeap( GetProcessHeap(), 0, t );
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1633,8 +1673,7 @@ static NTSTATUS alloc_thread_tls(void)
|
||||||
void **pointers;
|
void **pointers;
|
||||||
UINT i, size;
|
UINT i, size;
|
||||||
|
|
||||||
if (!(pointers = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
|
if (!(pointers = alloc_tls_memory( TRUE, tls_module_count * sizeof(*pointers) )))
|
||||||
tls_module_count * sizeof(*pointers) )))
|
|
||||||
return STATUS_NO_MEMORY;
|
return STATUS_NO_MEMORY;
|
||||||
|
|
||||||
for (i = 0; i < tls_module_count; i++)
|
for (i = 0; i < tls_module_count; i++)
|
||||||
|
@ -1645,10 +1684,10 @@ static NTSTATUS alloc_thread_tls(void)
|
||||||
size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
|
size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
|
||||||
if (!size && !dir->SizeOfZeroFill) continue;
|
if (!size && !dir->SizeOfZeroFill) continue;
|
||||||
|
|
||||||
if (!(pointers[i] = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill )))
|
if (!(pointers[i] = alloc_tls_memory( FALSE, size + dir->SizeOfZeroFill )))
|
||||||
{
|
{
|
||||||
while (i) RtlFreeHeap( GetProcessHeap(), 0, pointers[--i] );
|
while (i) free_tls_memory( pointers[--i] );
|
||||||
RtlFreeHeap( GetProcessHeap(), 0, pointers );
|
free_tls_memory( pointers );
|
||||||
return STATUS_NO_MEMORY;
|
return STATUS_NO_MEMORY;
|
||||||
}
|
}
|
||||||
memcpy( pointers[i], (void *)dir->StartAddressOfRawData, size );
|
memcpy( pointers[i], (void *)dir->StartAddressOfRawData, size );
|
||||||
|
@ -1656,6 +1695,7 @@ static NTSTATUS alloc_thread_tls(void)
|
||||||
|
|
||||||
TRACE( "slot %u: %u/%lu bytes at %p\n", i, size, dir->SizeOfZeroFill, pointers[i] );
|
TRACE( "slot %u: %u/%lu bytes at %p\n", i, size, dir->SizeOfZeroFill, pointers[i] );
|
||||||
}
|
}
|
||||||
|
++tls_thread_count;
|
||||||
NtCurrentTeb()->ThreadLocalStoragePointer = pointers;
|
NtCurrentTeb()->ThreadLocalStoragePointer = pointers;
|
||||||
#ifdef __x86_64__ /* macOS-specific hack */
|
#ifdef __x86_64__ /* macOS-specific hack */
|
||||||
if (NtCurrentTeb()->Instrumentation[0])
|
if (NtCurrentTeb()->Instrumentation[0])
|
||||||
|
@ -3947,12 +3987,13 @@ void WINAPI LdrShutdownThread(void)
|
||||||
if ((pointers = NtCurrentTeb()->ThreadLocalStoragePointer))
|
if ((pointers = NtCurrentTeb()->ThreadLocalStoragePointer))
|
||||||
{
|
{
|
||||||
NtCurrentTeb()->ThreadLocalStoragePointer = NULL;
|
NtCurrentTeb()->ThreadLocalStoragePointer = NULL;
|
||||||
|
--tls_thread_count;
|
||||||
#ifdef __x86_64__ /* macOS-specific hack */
|
#ifdef __x86_64__ /* macOS-specific hack */
|
||||||
if (NtCurrentTeb()->Instrumentation[0])
|
if (NtCurrentTeb()->Instrumentation[0])
|
||||||
((TEB *)NtCurrentTeb()->Instrumentation[0])->ThreadLocalStoragePointer = NULL;
|
((TEB *)NtCurrentTeb()->Instrumentation[0])->ThreadLocalStoragePointer = NULL;
|
||||||
#endif
|
#endif
|
||||||
for (i = 0; i < tls_module_count; i++) RtlFreeHeap( GetProcessHeap(), 0, pointers[i] );
|
for (i = 0; i < tls_module_count; i++) free_tls_memory( pointers[i] );
|
||||||
RtlFreeHeap( GetProcessHeap(), 0, pointers );
|
free_tls_memory( pointers );
|
||||||
}
|
}
|
||||||
RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 2 );
|
RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 2 );
|
||||||
NtCurrentTeb()->FlsSlots = NULL;
|
NtCurrentTeb()->FlsSlots = NULL;
|
||||||
|
|
|
@ -4087,6 +4087,278 @@ static void test_processor_idle_cycle_time(void)
|
||||||
ok( size == cpu_count * sizeof(*buffer), "got %#lx.\n", size );
|
ok( size == cpu_count * sizeof(*buffer), "got %#lx.\n", size );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DWORD WINAPI test_set_process_tls_info_thread(void *param)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_set_process_tls_info(void)
|
||||||
|
{
|
||||||
|
THREAD_BASIC_INFORMATION tbi;
|
||||||
|
TEB *teb = NtCurrentTeb(), *thread_teb;
|
||||||
|
char buffer[1024];
|
||||||
|
PROCESS_TLS_INFORMATION *tlsinfo = (PROCESS_TLS_INFORMATION *)buffer;
|
||||||
|
void **save_tls_pointers[2];
|
||||||
|
void *tls_pointer[4], *new_tls_pointer[4], *tls_pointer2[4], *new_tls_pointer2[4];
|
||||||
|
unsigned int i;
|
||||||
|
DWORD thread_id, curr_thread_id = GetCurrentThreadId();
|
||||||
|
NTSTATUS status;
|
||||||
|
HANDLE thread;
|
||||||
|
BOOL wow = is_wow64 && !old_wow64;
|
||||||
|
|
||||||
|
thread = CreateThread( NULL, 0, test_set_process_tls_info_thread, NULL, CREATE_SUSPENDED, &thread_id );
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* workaround currently present Wine bug when thread teb may be not available immediately
|
||||||
|
* after creating a thread before it is initialized on the Unix side. */
|
||||||
|
Sleep( 1 );
|
||||||
|
status = NtQueryInformationThread( thread, ThreadBasicInformation, &tbi, sizeof(tbi), NULL );
|
||||||
|
ok( !status, "got %#lx.\n", status );
|
||||||
|
} while (!(thread_teb = tbi.TebBaseAddress));
|
||||||
|
ok( !thread_teb->ThreadLocalStoragePointer, "got %p.\n", thread_teb->ThreadLocalStoragePointer );
|
||||||
|
|
||||||
|
save_tls_pointers[0] = teb->ThreadLocalStoragePointer;
|
||||||
|
save_tls_pointers[1] = thread_teb->ThreadLocalStoragePointer;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(tls_pointer); ++i)
|
||||||
|
{
|
||||||
|
tls_pointer[i] = (void *)(ULONG_PTR)(i + 1);
|
||||||
|
new_tls_pointer[i] = (void *)(ULONG_PTR)(i + 20);
|
||||||
|
}
|
||||||
|
teb->ThreadLocalStoragePointer = tls_pointer;
|
||||||
|
|
||||||
|
/* This flag probably requests WOW64 teb update. */
|
||||||
|
tlsinfo->Flags = 1;
|
||||||
|
tlsinfo->ThreadDataCount = 1;
|
||||||
|
tlsinfo->OperationType = ProcessTlsReplaceVector;
|
||||||
|
tlsinfo->TlsVectorLength = 2;
|
||||||
|
tlsinfo->ThreadData[0].Flags = 0;
|
||||||
|
tlsinfo->ThreadData[0].ThreadId = thread_id;
|
||||||
|
tlsinfo->ThreadData[0].TlsVector = new_tls_pointer;
|
||||||
|
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||||
|
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||||
|
if (wow)
|
||||||
|
{
|
||||||
|
ok( !status, "got %#lx.\n", status );
|
||||||
|
ok( tlsinfo->Flags == 1, "got %#lx.\n", tlsinfo->Flags );
|
||||||
|
ok( tlsinfo->ThreadData[0].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||||
|
ok( tlsinfo->ThreadData[0].ThreadId == curr_thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ok( status == STATUS_INVALID_PARAMETER, "got %#lx.\n", status );
|
||||||
|
ok( tlsinfo->Flags == 1, "got %#lx.\n", tlsinfo->Flags );
|
||||||
|
ok( !tlsinfo->ThreadData[0].Flags, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||||
|
ok( tlsinfo->ThreadData[0].ThreadId == thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Other PROCESS_TLS_INFORMATION flags are invalid. STATUS_INFO_LENGTH_MISMATCH is weird but that's for any flag
|
||||||
|
* besides 1. */
|
||||||
|
tlsinfo->Flags = 2;
|
||||||
|
tlsinfo->ThreadData[0].Flags = 0;
|
||||||
|
tlsinfo->ThreadData[0].ThreadId = thread_id;
|
||||||
|
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||||
|
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||||
|
ok( status == STATUS_INFO_LENGTH_MISMATCH, "got %#lx.\n", status );
|
||||||
|
ok( tlsinfo->Flags == 2, "got %#lx.\n", tlsinfo->Flags );
|
||||||
|
ok( !tlsinfo->ThreadData[0].Flags, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||||
|
ok( tlsinfo->ThreadData[0].ThreadId == thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||||
|
|
||||||
|
/* Nonzero THREAD_TLS_INFORMATION flags on input are invalid. */
|
||||||
|
tlsinfo->Flags = 0;
|
||||||
|
tlsinfo->ThreadData[0].Flags = 1;
|
||||||
|
tlsinfo->ThreadData[0].ThreadId = thread_id;
|
||||||
|
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||||
|
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||||
|
ok( status == STATUS_INVALID_PARAMETER, "got %#lx.\n", status );
|
||||||
|
ok( !tlsinfo->Flags, "got %#lx.\n", tlsinfo->Flags );
|
||||||
|
ok( tlsinfo->ThreadData[0].Flags == 1, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||||
|
ok( tlsinfo->ThreadData[0].ThreadId == thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||||
|
|
||||||
|
tlsinfo->ThreadData[0].Flags = 0;
|
||||||
|
tlsinfo->OperationType = MaxProcessTlsOperation;
|
||||||
|
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||||
|
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||||
|
/* Unknown operation type. */
|
||||||
|
ok( status == STATUS_INFO_LENGTH_MISMATCH || status == STATUS_INVALID_PARAMETER, "got %#lx.\n", status );
|
||||||
|
|
||||||
|
tlsinfo->OperationType = ProcessTlsReplaceVector;
|
||||||
|
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||||
|
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]) + 8);
|
||||||
|
/* Larger data size. */
|
||||||
|
ok( (!wow && status == STATUS_INFO_LENGTH_MISMATCH) || (wow && !status), "got %#lx.\n", status );
|
||||||
|
|
||||||
|
/* Zero thread count. */
|
||||||
|
tlsinfo->ThreadData[0].Flags = 0;
|
||||||
|
tlsinfo->ThreadDataCount = 0;
|
||||||
|
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||||
|
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||||
|
ok( status == STATUS_INFO_LENGTH_MISMATCH, "got %#lx.\n", status );
|
||||||
|
ok( !tlsinfo->Flags, "got %#lx.\n", tlsinfo->Flags );
|
||||||
|
|
||||||
|
tlsinfo->ThreadDataCount = 1;
|
||||||
|
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||||
|
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||||
|
ok( status == STATUS_SUCCESS, "got %#lx.\n", status );
|
||||||
|
ok( !tlsinfo->Flags, "got %#lx.\n", tlsinfo->Flags );
|
||||||
|
ok( tlsinfo->ThreadData[0].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||||
|
/* ThreadId is output parameter, ignored on input and contains the thread where the data were assigned on
|
||||||
|
* output. */
|
||||||
|
ok( tlsinfo->ThreadData[0].ThreadId == curr_thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||||
|
/* TlsVector contains the repaced vector on output. */
|
||||||
|
ok( tlsinfo->ThreadData[0].TlsVector == tls_pointer, "got %p.\n", tlsinfo->ThreadData[0].TlsVector );
|
||||||
|
ok( teb->ThreadLocalStoragePointer == new_tls_pointer, "wrong vector.\n" );
|
||||||
|
for (i = 0; i < ARRAY_SIZE(tls_pointer); ++i)
|
||||||
|
{
|
||||||
|
ok( tls_pointer[i] == (void *)(ULONG_PTR)(i + 1), "got %p.\n", tls_pointer );
|
||||||
|
/* TlsVectorLength pointers are copied from the old vector to the new one. */
|
||||||
|
if (i < 2)
|
||||||
|
ok( new_tls_pointer[i] == (void *)(ULONG_PTR)(i + 1), "got %p.\n", tls_pointer );
|
||||||
|
else
|
||||||
|
ok( new_tls_pointer[i] == (void *)(ULONG_PTR)(i + 20), "got %p.\n", tls_pointer );
|
||||||
|
}
|
||||||
|
|
||||||
|
teb->ThreadLocalStoragePointer = NULL;
|
||||||
|
tlsinfo->ThreadData[0].Flags = 0;
|
||||||
|
tlsinfo->ThreadData[0].TlsVector = new_tls_pointer;
|
||||||
|
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||||
|
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||||
|
ok( status == STATUS_SUCCESS, "got %#lx.\n", status );
|
||||||
|
/* Threads with NULL ThreadLocalStoragePointer are ignored. */
|
||||||
|
ok( !tlsinfo->Flags, "got %#lx.\n", tlsinfo->Flags );
|
||||||
|
ok( !tlsinfo->ThreadData[0].Flags, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||||
|
ok( tlsinfo->ThreadData[0].TlsVector == new_tls_pointer, "got %p.\n", tlsinfo->ThreadData[0].TlsVector );
|
||||||
|
|
||||||
|
memcpy( tls_pointer2, tls_pointer, sizeof(tls_pointer2) );
|
||||||
|
thread_teb->ThreadLocalStoragePointer = tls_pointer2;
|
||||||
|
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||||
|
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||||
|
ok( status == STATUS_SUCCESS, "got %#lx.\n", status );
|
||||||
|
ok( tlsinfo->ThreadData[0].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||||
|
ok( thread_teb->ThreadLocalStoragePointer == new_tls_pointer, "wrong vector.\n" );
|
||||||
|
ok( tlsinfo->ThreadData[0].ThreadId == thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||||
|
ok( tlsinfo->ThreadData[0].TlsVector == tls_pointer2, "got %p.\n", tlsinfo->ThreadData[0].TlsVector );
|
||||||
|
|
||||||
|
/* Two eligible threads, data for only one are provided, that succeeds. */
|
||||||
|
teb->ThreadLocalStoragePointer = tls_pointer;
|
||||||
|
thread_teb->ThreadLocalStoragePointer = tls_pointer2;
|
||||||
|
tlsinfo->ThreadData[0].Flags = 0;
|
||||||
|
tlsinfo->ThreadData[0].TlsVector = new_tls_pointer;
|
||||||
|
thread_teb->ThreadLocalStoragePointer = tls_pointer2;
|
||||||
|
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||||
|
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||||
|
ok( status == STATUS_SUCCESS, "got %#lx.\n", status );
|
||||||
|
ok( tlsinfo->ThreadDataCount == 1, "got %#lx.\n", tlsinfo->ThreadDataCount );
|
||||||
|
ok( tlsinfo->ThreadData[0].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||||
|
ok( teb->ThreadLocalStoragePointer == new_tls_pointer, "wrong vector.\n" );
|
||||||
|
ok( tlsinfo->ThreadData[0].ThreadId == curr_thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||||
|
ok( tlsinfo->ThreadData[0].TlsVector == tls_pointer, "got %p.\n", tlsinfo->ThreadData[0].TlsVector );
|
||||||
|
ok( thread_teb->ThreadLocalStoragePointer == tls_pointer2, "wrong vector.\n" );
|
||||||
|
|
||||||
|
/* Set for both threads at once as probably intended. Provide an extra data for the missing third thread
|
||||||
|
* which won't be used. */
|
||||||
|
teb->ThreadLocalStoragePointer = tls_pointer;
|
||||||
|
thread_teb->ThreadLocalStoragePointer = tls_pointer2;
|
||||||
|
memcpy( new_tls_pointer2, new_tls_pointer, sizeof(new_tls_pointer2) );
|
||||||
|
tlsinfo->ThreadDataCount = 3;
|
||||||
|
tlsinfo->ThreadData[0].TlsVector = new_tls_pointer;
|
||||||
|
tlsinfo->ThreadData[0].Flags = 0;
|
||||||
|
tlsinfo->ThreadData[1].TlsVector = new_tls_pointer2;
|
||||||
|
tlsinfo->ThreadData[1].Flags = 0;
|
||||||
|
tlsinfo->ThreadData[2].TlsVector = (void *)0xdeadbeef;
|
||||||
|
tlsinfo->ThreadData[2].Flags = 0;
|
||||||
|
tlsinfo->ThreadData[2].ThreadId = 0xdeadbeef;
|
||||||
|
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||||
|
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||||
|
ok( status == STATUS_SUCCESS, "got %#lx.\n", status );
|
||||||
|
ok( !tlsinfo->Flags, "got %#lx.\n", tlsinfo->Flags );
|
||||||
|
ok( tlsinfo->ThreadDataCount == 3, "got %#lx.\n", tlsinfo->ThreadDataCount );
|
||||||
|
ok( tlsinfo->ThreadData[0].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||||
|
ok( teb->ThreadLocalStoragePointer == new_tls_pointer, "wrong vector.\n" );
|
||||||
|
ok( tlsinfo->ThreadData[0].ThreadId == curr_thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||||
|
ok( tlsinfo->ThreadData[0].TlsVector == tls_pointer, "got %p.\n", tlsinfo->ThreadData[0].TlsVector );
|
||||||
|
ok( tlsinfo->ThreadData[1].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[1].Flags );
|
||||||
|
ok( teb->ThreadLocalStoragePointer == new_tls_pointer, "wrong vector.\n" );
|
||||||
|
ok( tlsinfo->ThreadData[1].ThreadId == thread_id, "got %#Ix.\n", tlsinfo->ThreadData[1].ThreadId );
|
||||||
|
ok( tlsinfo->ThreadData[1].TlsVector == tls_pointer2, "got %p.\n", tlsinfo->ThreadData[1].TlsVector );
|
||||||
|
ok( !tlsinfo->ThreadData[2].Flags, "got %#lx.\n", tlsinfo->ThreadData[2].Flags );
|
||||||
|
ok( tlsinfo->ThreadData[2].ThreadId == 0xdeadbeef, "got %#Ix.\n", tlsinfo->ThreadData[2].ThreadId );
|
||||||
|
ok( tlsinfo->ThreadData[2].TlsVector == (void *)0xdeadbeef, "got %p.\n", tlsinfo->ThreadData[2].TlsVector );
|
||||||
|
|
||||||
|
/* Test with unaccessible data. */
|
||||||
|
tlsinfo->ThreadData[0].TlsVector = new_tls_pointer;
|
||||||
|
tlsinfo->ThreadData[0].ThreadId = 0;
|
||||||
|
tlsinfo->ThreadData[0].Flags = 0;
|
||||||
|
tlsinfo->ThreadData[1].TlsVector = new_tls_pointer2;
|
||||||
|
tlsinfo->ThreadData[1].ThreadId = 0;
|
||||||
|
tlsinfo->ThreadData[1].Flags = 0;
|
||||||
|
teb->ThreadLocalStoragePointer = tls_pointer;
|
||||||
|
thread_teb->ThreadLocalStoragePointer = (void *)0xdeadbee0;
|
||||||
|
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||||
|
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||||
|
ok( status == STATUS_ACCESS_VIOLATION, "got %#lx.\n", status );
|
||||||
|
ok( !tlsinfo->Flags, "got %#lx.\n", tlsinfo->Flags );
|
||||||
|
ok( tlsinfo->ThreadDataCount == 3, "got %#lx.\n", tlsinfo->ThreadDataCount );
|
||||||
|
if (wow)
|
||||||
|
{
|
||||||
|
ok( !tlsinfo->ThreadData[0].Flags, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||||
|
ok( !tlsinfo->ThreadData[0].ThreadId, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||||
|
ok( tlsinfo->ThreadData[0].TlsVector == new_tls_pointer, "got %p.\n", tlsinfo->ThreadData[0].TlsVector );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ok( tlsinfo->ThreadData[0].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||||
|
ok( tlsinfo->ThreadData[0].ThreadId == curr_thread_id, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||||
|
ok( tlsinfo->ThreadData[0].TlsVector == tls_pointer, "got %p.\n", tlsinfo->ThreadData[0].TlsVector );
|
||||||
|
}
|
||||||
|
ok( teb->ThreadLocalStoragePointer == new_tls_pointer, "wrong vector.\n" );
|
||||||
|
ok( !tlsinfo->ThreadData[1].Flags, "got %#lx.\n", tlsinfo->ThreadData[1].Flags );
|
||||||
|
ok( teb->ThreadLocalStoragePointer == new_tls_pointer, "wrong vector.\n" );
|
||||||
|
ok( !tlsinfo->ThreadData[1].ThreadId, "got %#Ix.\n", tlsinfo->ThreadData[1].ThreadId );
|
||||||
|
ok( tlsinfo->ThreadData[1].TlsVector == new_tls_pointer2, "got %p.\n", tlsinfo->ThreadData[1].TlsVector );
|
||||||
|
ok( !tlsinfo->ThreadData[2].Flags, "got %#lx.\n", tlsinfo->ThreadData[2].Flags );
|
||||||
|
ok( tlsinfo->ThreadData[2].ThreadId == 0xdeadbeef, "got %#Ix.\n", tlsinfo->ThreadData[2].ThreadId );
|
||||||
|
ok( tlsinfo->ThreadData[2].TlsVector == (void *)0xdeadbeef, "got %p.\n", tlsinfo->ThreadData[2].TlsVector );
|
||||||
|
|
||||||
|
/* Test replacing TLS index. */
|
||||||
|
teb->ThreadLocalStoragePointer = new_tls_pointer;
|
||||||
|
thread_teb->ThreadLocalStoragePointer = new_tls_pointer2;
|
||||||
|
new_tls_pointer[1] = (void *)0xcccccccc;
|
||||||
|
new_tls_pointer2[1] = (void *)0xdddddddd;
|
||||||
|
tlsinfo->ThreadDataCount = 3;
|
||||||
|
tlsinfo->OperationType = ProcessTlsReplaceIndex;
|
||||||
|
tlsinfo->TlsIndex = 1;
|
||||||
|
for (i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
tlsinfo->ThreadData[i].Flags = 0;
|
||||||
|
tlsinfo->ThreadData[i].ThreadId = 0xdeadbeef;
|
||||||
|
tlsinfo->ThreadData[i].TlsModulePointer = (void *)((ULONG_PTR)i + 1);
|
||||||
|
}
|
||||||
|
status = NtSetInformationProcess( GetCurrentProcess(), ProcessTlsInformation, tlsinfo,
|
||||||
|
offsetof(PROCESS_TLS_INFORMATION, ThreadData[tlsinfo->ThreadDataCount]));
|
||||||
|
ok( status == STATUS_SUCCESS, "got %#lx.\n", status );
|
||||||
|
ok( !tlsinfo->Flags, "got %#lx.\n", tlsinfo->Flags );
|
||||||
|
ok( tlsinfo->ThreadDataCount == 3, "got %#lx.\n", tlsinfo->ThreadDataCount );
|
||||||
|
ok( tlsinfo->ThreadData[0].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[0].Flags );
|
||||||
|
ok( (ULONG_PTR)new_tls_pointer[1] == 1, "got %p.\n", new_tls_pointer[1] );
|
||||||
|
ok( tlsinfo->ThreadData[0].ThreadId == 0xdeadbeef, "got %#Ix.\n", tlsinfo->ThreadData[0].ThreadId );
|
||||||
|
ok( (ULONG_PTR)tlsinfo->ThreadData[0].TlsModulePointer == 0xcccccccc, "got %p.\n", tlsinfo->ThreadData[0].TlsModulePointer );
|
||||||
|
ok( tlsinfo->ThreadData[1].Flags == THREAD_TLS_INFORMATION_ASSIGNED, "got %#lx.\n", tlsinfo->ThreadData[1].Flags );
|
||||||
|
ok( (ULONG_PTR)new_tls_pointer2[1] == 2, "got %p.\n", new_tls_pointer2[1] );
|
||||||
|
ok( tlsinfo->ThreadData[1].ThreadId == 0xdeadbeef, "got %#Ix.\n", tlsinfo->ThreadData[1].ThreadId );
|
||||||
|
ok( (ULONG_PTR)tlsinfo->ThreadData[1].TlsModulePointer == 0xdddddddd, "got %p.\n", tlsinfo->ThreadData[1].TlsModulePointer );
|
||||||
|
ok( !tlsinfo->ThreadData[2].Flags, "got %#lx.\n", tlsinfo->ThreadData[2].Flags );
|
||||||
|
ok( tlsinfo->ThreadData[2].ThreadId == 0xdeadbeef, "got %#Ix.\n", tlsinfo->ThreadData[2].ThreadId );
|
||||||
|
ok( (ULONG_PTR)tlsinfo->ThreadData[2].TlsModulePointer == 3, "got %p.\n", tlsinfo->ThreadData[2].TlsModulePointer );
|
||||||
|
|
||||||
|
/* Restore original TLS data. */
|
||||||
|
teb->ThreadLocalStoragePointer = save_tls_pointers[0];
|
||||||
|
thread_teb->ThreadLocalStoragePointer = save_tls_pointers[1];
|
||||||
|
ResumeThread( thread );
|
||||||
|
WaitForSingleObject( thread, INFINITE );
|
||||||
|
CloseHandle( thread );
|
||||||
|
}
|
||||||
|
|
||||||
START_TEST(info)
|
START_TEST(info)
|
||||||
{
|
{
|
||||||
char **argv;
|
char **argv;
|
||||||
|
@ -4167,4 +4439,5 @@ START_TEST(info)
|
||||||
test_process_token(argc, argv);
|
test_process_token(argc, argv);
|
||||||
test_process_id();
|
test_process_id();
|
||||||
test_processor_idle_cycle_time();
|
test_processor_idle_cycle_time();
|
||||||
|
test_set_process_tls_info();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1711,6 +1711,33 @@ NTSTATUS WINAPI NtSetInformationProcess( HANDLE handle, PROCESSINFOCLASS class,
|
||||||
process_error_mode = *(UINT *)info;
|
process_error_mode = *(UINT *)info;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ProcessTlsInformation:
|
||||||
|
{
|
||||||
|
PROCESS_TLS_INFORMATION *t = info;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (handle != NtCurrentProcess())
|
||||||
|
{
|
||||||
|
FIXME( "ProcessTlsInformation is not supported for the other process yet, handle %p.\n", handle );
|
||||||
|
return STATUS_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size < sizeof(*t) || size != offsetof(PROCESS_TLS_INFORMATION, ThreadData[t->ThreadDataCount]))
|
||||||
|
return STATUS_INFO_LENGTH_MISMATCH;
|
||||||
|
if (t->Flags & ~PROCESS_TLS_INFORMATION_WOW64)
|
||||||
|
{
|
||||||
|
WARN( "ProcessTlsInformation: unknown flags %#x.\n", (int)t->Flags );
|
||||||
|
return STATUS_INFO_LENGTH_MISMATCH;
|
||||||
|
}
|
||||||
|
if (t->Flags & PROCESS_TLS_INFORMATION_WOW64 && !(is_win64 && is_wow64()))
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
if (t->OperationType >= MaxProcessTlsOperation) return STATUS_INFO_LENGTH_MISMATCH;
|
||||||
|
for (i = 0; i < t->ThreadDataCount; ++i)
|
||||||
|
if (t->ThreadData[i].Flags) return STATUS_INVALID_PARAMETER;
|
||||||
|
ret = virtual_set_tls_information( t );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ProcessAffinityMask:
|
case ProcessAffinityMask:
|
||||||
{
|
{
|
||||||
const ULONG_PTR system_mask = get_system_affinity_mask();
|
const ULONG_PTR system_mask = get_system_affinity_mask();
|
||||||
|
|
|
@ -282,6 +282,7 @@ extern TEB *virtual_alloc_first_teb(void);
|
||||||
extern NTSTATUS virtual_alloc_teb( TEB **ret_teb );
|
extern NTSTATUS virtual_alloc_teb( TEB **ret_teb );
|
||||||
extern void virtual_free_teb( TEB *teb );
|
extern void virtual_free_teb( TEB *teb );
|
||||||
extern NTSTATUS virtual_clear_tls_index( ULONG index );
|
extern NTSTATUS virtual_clear_tls_index( ULONG index );
|
||||||
|
extern NTSTATUS virtual_set_tls_information( PROCESS_TLS_INFORMATION *t );
|
||||||
extern NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, ULONG_PTR limit_low, ULONG_PTR limit_high,
|
extern NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, ULONG_PTR limit_low, ULONG_PTR limit_high,
|
||||||
SIZE_T reserve_size, SIZE_T commit_size, BOOL guard_page );
|
SIZE_T reserve_size, SIZE_T commit_size, BOOL guard_page );
|
||||||
extern void virtual_map_user_shared_data(void);
|
extern void virtual_map_user_shared_data(void);
|
||||||
|
|
|
@ -3874,6 +3874,98 @@ NTSTATUS virtual_clear_tls_index( ULONG index )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* virtual_set_tls_information_teb
|
||||||
|
*/
|
||||||
|
static NTSTATUS virtual_set_tls_information_teb( PROCESS_TLS_INFORMATION *t, unsigned int *idx, TEB *teb )
|
||||||
|
{
|
||||||
|
__TRY
|
||||||
|
{
|
||||||
|
#ifdef _WIN64
|
||||||
|
if (t->Flags & PROCESS_TLS_INFORMATION_WOW64)
|
||||||
|
{
|
||||||
|
WOW_TEB *wow_teb = get_wow_teb( teb );
|
||||||
|
ULONG *ptr;
|
||||||
|
|
||||||
|
if (wow_teb && wow_teb->ThreadLocalStoragePointer)
|
||||||
|
{
|
||||||
|
if (t->OperationType == ProcessTlsReplaceVector)
|
||||||
|
{
|
||||||
|
ptr = t->ThreadData[*idx].TlsVector;
|
||||||
|
memcpy( ptr, ULongToPtr( wow_teb->ThreadLocalStoragePointer ), sizeof(*ptr) * t->TlsVectorLength );
|
||||||
|
t->ThreadData[*idx].TlsVector = ULongToPtr( InterlockedExchange( (LONG *)&wow_teb->ThreadLocalStoragePointer, PtrToLong( ptr )));
|
||||||
|
t->ThreadData[*idx].ThreadId = wow_teb->ClientId.UniqueThread;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ptr = ULongToPtr( wow_teb->ThreadLocalStoragePointer );
|
||||||
|
t->ThreadData[*idx].TlsModulePointer =
|
||||||
|
ULongToPtr( InterlockedExchange( (LONG *)&ptr[t->TlsIndex],
|
||||||
|
PtrToLong( t->ThreadData[*idx].TlsModulePointer )));
|
||||||
|
}
|
||||||
|
t->ThreadData[*idx].Flags = THREAD_TLS_INFORMATION_ASSIGNED;
|
||||||
|
++*idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
if (teb->ThreadLocalStoragePointer)
|
||||||
|
{
|
||||||
|
void **ptr;
|
||||||
|
|
||||||
|
if (t->OperationType == ProcessTlsReplaceVector)
|
||||||
|
{
|
||||||
|
ptr = t->ThreadData[*idx].TlsVector;
|
||||||
|
memcpy( ptr, teb->ThreadLocalStoragePointer, sizeof(*ptr) * t->TlsVectorLength );
|
||||||
|
t->ThreadData[*idx].TlsVector = InterlockedExchangePointer( &teb->ThreadLocalStoragePointer, ptr );
|
||||||
|
t->ThreadData[*idx].ThreadId = HandleToULong( teb->ClientId.UniqueThread );
|
||||||
|
#ifdef __x86_64__ /* macOS-specific hack */
|
||||||
|
if (teb->Instrumentation[0]) ((TEB *)teb->Instrumentation[0])->ThreadLocalStoragePointer = ptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ptr = teb->ThreadLocalStoragePointer;
|
||||||
|
t->ThreadData[*idx].TlsModulePointer = InterlockedExchangePointer( &ptr[t->TlsIndex],
|
||||||
|
t->ThreadData[*idx].TlsModulePointer );
|
||||||
|
}
|
||||||
|
t->ThreadData[*idx].Flags = THREAD_TLS_INFORMATION_ASSIGNED;
|
||||||
|
++*idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__EXCEPT
|
||||||
|
{
|
||||||
|
return STATUS_ACCESS_VIOLATION;
|
||||||
|
}
|
||||||
|
__ENDTRY
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* virtual_set_tls_information
|
||||||
|
*/
|
||||||
|
NTSTATUS virtual_set_tls_information( PROCESS_TLS_INFORMATION *t )
|
||||||
|
{
|
||||||
|
struct ntdll_thread_data *thread_data;
|
||||||
|
NTSTATUS ret = STATUS_SUCCESS;
|
||||||
|
unsigned int idx = 0;
|
||||||
|
sigset_t sigset;
|
||||||
|
|
||||||
|
server_enter_uninterrupted_section( &virtual_mutex, &sigset );
|
||||||
|
LIST_FOR_EACH_ENTRY_REV( thread_data, &teb_list, struct ntdll_thread_data, entry )
|
||||||
|
{
|
||||||
|
TEB *teb = CONTAINING_RECORD( thread_data, TEB, GdiTebBatch );
|
||||||
|
|
||||||
|
if (idx == t->ThreadDataCount) break;
|
||||||
|
if ((ret = virtual_set_tls_information_teb( t, &idx, teb ))) break;
|
||||||
|
}
|
||||||
|
server_leave_uninterrupted_section( &virtual_mutex, &sigset );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* virtual_alloc_thread_stack
|
* virtual_alloc_thread_stack
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -894,6 +894,39 @@ NTSTATUS WINAPI wow64_NtSetInformationProcess( UINT *args )
|
||||||
}
|
}
|
||||||
else return STATUS_INVALID_PARAMETER;
|
else return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
case ProcessTlsInformation:
|
||||||
|
{
|
||||||
|
PROCESS_TLS_INFORMATION32 *t32 = ptr;
|
||||||
|
PROCESS_TLS_INFORMATION *t;
|
||||||
|
ULONG i;
|
||||||
|
|
||||||
|
if (len >= sizeof(*t32) && len >= offsetof(PROCESS_TLS_INFORMATION32, ThreadData[t32->ThreadDataCount]))
|
||||||
|
{
|
||||||
|
t = Wow64AllocateTemp( offsetof(PROCESS_TLS_INFORMATION, ThreadData[t32->ThreadDataCount]) );
|
||||||
|
t->Flags = t32->Flags ? t32->Flags : PROCESS_TLS_INFORMATION_WOW64;
|
||||||
|
t->OperationType = t32->OperationType;
|
||||||
|
t->ThreadDataCount = t32->ThreadDataCount;
|
||||||
|
t->TlsIndex = t32->TlsIndex;
|
||||||
|
for (i = 0; i < t->ThreadDataCount; ++i)
|
||||||
|
{
|
||||||
|
t->ThreadData[i].Flags = t32->ThreadData[i].Flags;
|
||||||
|
t->ThreadData[i].ThreadId = t32->ThreadData[i].ThreadId;
|
||||||
|
t->ThreadData[i].TlsVector = ULongToPtr( t32->ThreadData[i].TlsVector );
|
||||||
|
}
|
||||||
|
if (!(status = NtSetInformationProcess( handle, class, t, offsetof(PROCESS_TLS_INFORMATION, ThreadData[t->ThreadDataCount]) )))
|
||||||
|
{
|
||||||
|
for (i = 0; i < t->ThreadDataCount; ++i)
|
||||||
|
{
|
||||||
|
t32->ThreadData[i].Flags = t->ThreadData[i].Flags;
|
||||||
|
t32->ThreadData[i].ThreadId = t->ThreadData[i].ThreadId;
|
||||||
|
t32->ThreadData[i].TlsVector = PtrToUlong( t->ThreadData[i].TlsVector );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
else return STATUS_INFO_LENGTH_MISMATCH;
|
||||||
|
}
|
||||||
|
|
||||||
case ProcessInstrumentationCallback: /* PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION */
|
case ProcessInstrumentationCallback: /* PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION */
|
||||||
if (len >= sizeof(ULONG))
|
if (len >= sizeof(ULONG))
|
||||||
{
|
{
|
||||||
|
|
|
@ -326,6 +326,30 @@ typedef struct
|
||||||
ULONG DefaultBase;
|
ULONG DefaultBase;
|
||||||
} RTL_PROCESS_MODULE_INFORMATION_EX32;
|
} RTL_PROCESS_MODULE_INFORMATION_EX32;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ULONG Flags;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
ULONG TlsVector;
|
||||||
|
ULONG TlsModulePointer;
|
||||||
|
};
|
||||||
|
ULONG ThreadId;
|
||||||
|
} THREAD_TLS_INFORMATION32;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ULONG Flags;
|
||||||
|
ULONG OperationType;
|
||||||
|
ULONG ThreadDataCount;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
ULONG TlsIndex;
|
||||||
|
ULONG TlsVectorLength;
|
||||||
|
};
|
||||||
|
THREAD_TLS_INFORMATION32 ThreadData[1];
|
||||||
|
} PROCESS_TLS_INFORMATION32;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
ULONG BaseAddress;
|
ULONG BaseAddress;
|
||||||
|
|
|
@ -2668,6 +2668,41 @@ typedef struct _PROCESS_CYCLE_TIME_INFORMATION {
|
||||||
ULONGLONG CurrentCycleCount;
|
ULONGLONG CurrentCycleCount;
|
||||||
} PROCESS_CYCLE_TIME_INFORMATION, *PPROCESS_CYCLE_TIME_INFORMATION;
|
} PROCESS_CYCLE_TIME_INFORMATION, *PPROCESS_CYCLE_TIME_INFORMATION;
|
||||||
|
|
||||||
|
typedef struct _THREAD_TLS_INFORMATION
|
||||||
|
{
|
||||||
|
ULONG Flags;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
void *TlsVector;
|
||||||
|
void *TlsModulePointer;
|
||||||
|
};
|
||||||
|
ULONG_PTR ThreadId;
|
||||||
|
} THREAD_TLS_INFORMATION, * PTHREAD_TLS_INFORMATION;
|
||||||
|
|
||||||
|
#define THREAD_TLS_INFORMATION_ASSIGNED 0x2
|
||||||
|
|
||||||
|
typedef enum _PROCESS_TLS_INFORMATION_TYPE
|
||||||
|
{
|
||||||
|
ProcessTlsReplaceIndex,
|
||||||
|
ProcessTlsReplaceVector,
|
||||||
|
MaxProcessTlsOperation
|
||||||
|
} PROCESS_TLS_INFORMATION_TYPE, *PPROCESS_TLS_INFORMATION_TYPE;
|
||||||
|
|
||||||
|
typedef struct _PROCESS_TLS_INFORMATION
|
||||||
|
{
|
||||||
|
ULONG Flags;
|
||||||
|
ULONG OperationType;
|
||||||
|
ULONG ThreadDataCount;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
ULONG TlsIndex;
|
||||||
|
ULONG TlsVectorLength;
|
||||||
|
};
|
||||||
|
THREAD_TLS_INFORMATION ThreadData[1];
|
||||||
|
} PROCESS_TLS_INFORMATION, *PPROCESS_TLS_INFORMATION;
|
||||||
|
|
||||||
|
#define PROCESS_TLS_INFORMATION_WOW64 1
|
||||||
|
|
||||||
typedef struct _PROCESS_STACK_ALLOCATION_INFORMATION
|
typedef struct _PROCESS_STACK_ALLOCATION_INFORMATION
|
||||||
{
|
{
|
||||||
SIZE_T ReserveSize;
|
SIZE_T ReserveSize;
|
||||||
|
|
Loading…
Reference in a new issue