From: Paul Gofman pgofman@codeweavers.com
--- dlls/kernel32/tests/module.c | 23 ++++++++++++++++ dlls/ntdll/loader.c | 51 ++++++++++++++++++++++++++++-------- 2 files changed, 63 insertions(+), 11 deletions(-)
diff --git a/dlls/kernel32/tests/module.c b/dlls/kernel32/tests/module.c index 0619ce5f747..3d6e195e23c 100644 --- a/dlls/kernel32/tests/module.c +++ b/dlls/kernel32/tests/module.c @@ -1708,7 +1708,10 @@ static void test_tls_links(void) TEB *teb = NtCurrentTeb(), *thread_teb; THREAD_BASIC_INFORMATION tbi; NTSTATUS status; + ULONG i, count; HANDLE thread; + SIZE_T size; + void **ptr;
ok(!!teb->ThreadLocalStoragePointer, "got NULL.\n");
@@ -1728,6 +1731,26 @@ static void test_tls_links(void) ResumeThread(thread); 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(!teb->TlsLinks.Flink, "got %p.\n", teb->TlsLinks.Flink); ok(!teb->TlsLinks.Blink, "got %p.\n", teb->TlsLinks.Blink); diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 617b0143b6d..5c9c9e4e923 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -1333,6 +1333,36 @@ static BOOL is_dll_native_subsystem( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_NT_H 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 * @@ -1399,13 +1429,13 @@ static BOOL alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
t->ThreadData[j].Flags = 0;
- if (!(new_ptr = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill ))) return FALSE; + if (!(new_ptr = alloc_tls_memory( FALSE, size + dir->SizeOfZeroFill ))) return FALSE; memcpy( new_ptr, (void *)dir->StartAddressOfRawData, size ); memset( (char *)new_ptr + size, 0, dir->SizeOfZeroFill );
if (t->OperationType == ProcessTlsReplaceVector) { - vector = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, tls_module_count * sizeof(*vector) ); + vector = alloc_tls_memory( TRUE, tls_module_count * sizeof(*vector) ); if (!vector) return FALSE; t->ThreadData[j].TlsVector = vector; vector[i] = new_ptr; @@ -1425,12 +1455,12 @@ static BOOL alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) { /* 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. */ - RtlFreeHeap( GetProcessHeap(), 0, ((void **)t->ThreadData[j].TlsVector)[i] ); + 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. */ - RtlFreeHeap( GetProcessHeap(), 0, t->ThreadData[j].TlsVector ); + free_tls_memory( t->ThreadData[j].TlsVector ); } } RtlFreeHeap( GetProcessHeap(), 0, t ); @@ -1643,8 +1673,7 @@ static NTSTATUS alloc_thread_tls(void) void **pointers; UINT i, size;
- if (!(pointers = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, - tls_module_count * sizeof(*pointers) ))) + if (!(pointers = alloc_tls_memory( TRUE, tls_module_count * sizeof(*pointers) ))) return STATUS_NO_MEMORY;
for (i = 0; i < tls_module_count; i++) @@ -1655,10 +1684,10 @@ static NTSTATUS alloc_thread_tls(void) size = dir->EndAddressOfRawData - dir->StartAddressOfRawData; 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] ); - RtlFreeHeap( GetProcessHeap(), 0, pointers ); + while (i) free_tls_memory( pointers[--i] ); + free_tls_memory( pointers ); return STATUS_NO_MEMORY; } memcpy( pointers[i], (void *)dir->StartAddressOfRawData, size ); @@ -3963,8 +3992,8 @@ void WINAPI LdrShutdownThread(void) if (NtCurrentTeb()->Instrumentation[0]) ((TEB *)NtCurrentTeb()->Instrumentation[0])->ThreadLocalStoragePointer = NULL; #endif - for (i = 0; i < tls_module_count; i++) RtlFreeHeap( GetProcessHeap(), 0, pointers[i] ); - RtlFreeHeap( GetProcessHeap(), 0, pointers ); + for (i = 0; i < tls_module_count; i++) free_tls_memory( pointers[i] ); + free_tls_memory( pointers ); } RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 2 ); NtCurrentTeb()->FlsSlots = NULL;