Commit a30a5287 authored by Evan Tang's avatar Evan Tang Committed by Alexandre Julliard

ntdll: TlsIndex should not actually contain tls indices.

It actually contains a -1 if the module has a tls slot and a 0 if it doesn't. Putting tls indices in it breaks initialization of the D runtime if a D dll is loaded into a tls-free exe and gets assigned tls slot 0, as it makes the D runtime think the OS hasn't initialized a tls slot: https://github.com/dlang/dmd/blob/6bf60ea0eb174631ede0074a77d3898d943e0b30/druntime/src/core/sys/windows/dll.d#L354-L355
parent 433bc127
...@@ -1222,7 +1222,7 @@ static BOOL is_dll_native_subsystem( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_NT_H ...@@ -1222,7 +1222,7 @@ static BOOL is_dll_native_subsystem( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_NT_H
* Allocate a TLS slot for a newly-loaded module. * Allocate a TLS slot for a newly-loaded module.
* The loader_section must be locked while calling this function. * The loader_section must be locked while calling this function.
*/ */
static SHORT 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, size;
...@@ -1230,10 +1230,10 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) ...@@ -1230,10 +1230,10 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
LIST_ENTRY *entry; LIST_ENTRY *entry;
if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size ))) if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size )))
return -1; return FALSE;
size = dir->EndAddressOfRawData - dir->StartAddressOfRawData; size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
if (!size && !dir->SizeOfZeroFill && !dir->AddressOfCallBacks) return -1; if (!size && !dir->SizeOfZeroFill && !dir->AddressOfCallBacks) return FALSE;
for (i = 0; i < tls_module_count; i++) for (i = 0; i < tls_module_count; i++)
{ {
...@@ -1255,7 +1255,7 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) ...@@ -1255,7 +1255,7 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
else else
new_ptr = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, tls_dirs, new_ptr = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, tls_dirs,
new_count * sizeof(*tls_dirs) ); new_count * sizeof(*tls_dirs) );
if (!new_ptr) return -1; if (!new_ptr) return FALSE;
/* resize the pointer block in all running threads */ /* resize the pointer block in all running threads */
for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink) for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
...@@ -1264,7 +1264,7 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) ...@@ -1264,7 +1264,7 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
void **old = teb->ThreadLocalStoragePointer; void **old = teb->ThreadLocalStoragePointer;
void **new = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*new)); void **new = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*new));
if (!new) return -1; if (!new) return FALSE;
if (old) memcpy( new, old, tls_module_count * sizeof(*new) ); if (old) memcpy( new, old, tls_module_count * sizeof(*new) );
teb->ThreadLocalStoragePointer = new; teb->ThreadLocalStoragePointer = new;
#ifdef __x86_64__ /* macOS-specific hack */ #ifdef __x86_64__ /* macOS-specific hack */
...@@ -1296,7 +1296,7 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) ...@@ -1296,7 +1296,7 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
*(DWORD *)dir->AddressOfIndex = i; *(DWORD *)dir->AddressOfIndex = i;
tls_dirs[i] = *dir; tls_dirs[i] = *dir;
return i; return TRUE;
} }
...@@ -1308,9 +1308,15 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) ...@@ -1308,9 +1308,15 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
*/ */
static void free_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) static void free_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
{ {
ULONG i = (USHORT)mod->TlsIndex; const IMAGE_TLS_DIRECTORY *dir;
ULONG i, size;
if (mod->TlsIndex != -1)
return;
if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size )))
return;
if (mod->TlsIndex == -1) return; i = *(ULONG*)dir->AddressOfIndex;
assert( i < tls_module_count ); assert( i < tls_module_count );
memset( &tls_dirs[i], 0, sizeof(tls_dirs[i]) ); memset( &tls_dirs[i], 0, sizeof(tls_dirs[i]) );
} }
...@@ -1374,7 +1380,7 @@ static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path ) ...@@ -1374,7 +1380,7 @@ static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS; /* already done */ if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS; /* already done */
wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS; wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
wm->ldr.TlsIndex = alloc_tls_slot( &wm->ldr ); if (alloc_tls_slot( &wm->ldr )) wm->ldr.TlsIndex = -1;
if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE, if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE,
IMAGE_DIRECTORY_ENTRY_IMPORT, &size ))) IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
...@@ -1431,7 +1437,7 @@ static WINE_MODREF *alloc_module( HMODULE hModule, const UNICODE_STRING *nt_name ...@@ -1431,7 +1437,7 @@ static WINE_MODREF *alloc_module( HMODULE hModule, const UNICODE_STRING *nt_name
wm->ldr.DllBase = hModule; wm->ldr.DllBase = hModule;
wm->ldr.SizeOfImage = nt->OptionalHeader.SizeOfImage; wm->ldr.SizeOfImage = nt->OptionalHeader.SizeOfImage;
wm->ldr.Flags = LDR_DONT_RESOLVE_REFS | (builtin ? LDR_WINE_INTERNAL : 0); wm->ldr.Flags = LDR_DONT_RESOLVE_REFS | (builtin ? LDR_WINE_INTERNAL : 0);
wm->ldr.TlsIndex = -1; wm->ldr.TlsIndex = 0;
wm->ldr.LoadCount = 1; wm->ldr.LoadCount = 1;
wm->CheckSum = nt->OptionalHeader.CheckSum; wm->CheckSum = nt->OptionalHeader.CheckSum;
wm->ldr.TimeDateStamp = nt->FileHeader.TimeDateStamp; wm->ldr.TimeDateStamp = nt->FileHeader.TimeDateStamp;
...@@ -1783,7 +1789,7 @@ NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule) ...@@ -1783,7 +1789,7 @@ NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
RtlEnterCriticalSection( &loader_section ); RtlEnterCriticalSection( &loader_section );
wm = get_modref( hModule ); wm = get_modref( hModule );
if (!wm || wm->ldr.TlsIndex != -1) if (!wm || wm->ldr.TlsIndex == -1)
ret = STATUS_DLL_NOT_FOUND; ret = STATUS_DLL_NOT_FOUND;
else else
wm->ldr.Flags |= LDR_NO_DLL_CALLS; wm->ldr.Flags |= LDR_NO_DLL_CALLS;
...@@ -3712,7 +3718,7 @@ void WINAPI LdrShutdownThread(void) ...@@ -3712,7 +3718,7 @@ void WINAPI LdrShutdownThread(void)
DLL_THREAD_DETACH, NULL ); DLL_THREAD_DETACH, NULL );
} }
if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_DETACH ); if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_DETACH );
RtlAcquirePebLock(); RtlAcquirePebLock();
if (NtCurrentTeb()->TlsLinks.Flink) RemoveEntryList( &NtCurrentTeb()->TlsLinks ); if (NtCurrentTeb()->TlsLinks.Flink) RemoveEntryList( &NtCurrentTeb()->TlsLinks );
...@@ -4216,7 +4222,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR ...@@ -4216,7 +4222,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR
NtTerminateProcess( GetCurrentProcess(), status ); NtTerminateProcess( GetCurrentProcess(), status );
} }
release_address_space(); release_address_space();
if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_PROCESS_ATTACH ); if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_PROCESS_ATTACH );
if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie ); if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
process_breakpoint(); process_breakpoint();
} }
...@@ -4225,7 +4231,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR ...@@ -4225,7 +4231,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR
if ((status = alloc_thread_tls()) != STATUS_SUCCESS) if ((status = alloc_thread_tls()) != STATUS_SUCCESS)
NtTerminateThread( GetCurrentThread(), status ); NtTerminateThread( GetCurrentThread(), status );
thread_attach(); thread_attach();
if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_ATTACH ); if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_ATTACH );
} }
RtlLeaveCriticalSection( &loader_section ); RtlLeaveCriticalSection( &loader_section );
......
...@@ -3788,6 +3788,31 @@ static void test_RtlFirstFreeAce(void) ...@@ -3788,6 +3788,31 @@ static void test_RtlFirstFreeAce(void)
HeapFree(GetProcessHeap(), 0, acl); HeapFree(GetProcessHeap(), 0, acl);
} }
static void test_TlsIndex(void)
{
LIST_ENTRY *root = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
for (LIST_ENTRY *entry = root->Flink; entry != root; entry = entry->Flink)
{
LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
if (lstrcmpiW(L"ntdll.dll", mod->BaseDllName.Buffer) == 0)
{
/* Pick ntdll as a dll that definitely won't have TLS */
ok(mod->TlsIndex == 0, "ntdll.dll TlsIndex: %d instead of 0\n", mod->TlsIndex);
}
else if (mod->DllBase == GetModuleHandleA(NULL))
{
/* mingw gcc doesn't support MSVC-style TLS */
/* If we do get a way to add tls to this exe, uncomment the following test: */
/* ok(mod->TlsIndex == -1, "Test exe TlsIndex: %d instead of -1\n", mod->TlsIndex); */
}
else
{
ok(mod->TlsIndex == 0 || mod->TlsIndex == -1, "%s TlsIndex: %d\n",
debugstr_w(mod->BaseDllName.Buffer), mod->TlsIndex);
}
}
}
START_TEST(rtl) START_TEST(rtl)
{ {
InitFunctionPtrs(); InitFunctionPtrs();
...@@ -3832,4 +3857,5 @@ START_TEST(rtl) ...@@ -3832,4 +3857,5 @@ START_TEST(rtl)
test_DbgPrint(); test_DbgPrint();
test_RtlDestroyHeap(); test_RtlDestroyHeap();
test_RtlFirstFreeAce(); test_RtlFirstFreeAce();
test_TlsIndex();
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment