WinSxS DLLs are found via find_actctx_dll(). When activation contexts are inactive, GetModuleHandle() shouldn't find WinSxS DLLs with the same base name of a normal DLL.
-- v2: ntdll: Exclude SxS DLLs when finding a DLL with its base name and no activation contexts. kernel32/tests: Add more GetModuleHandle() tests for WinSxS.
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/kernel32/tests/actctx.c | 47 +++++++++++++++++++++++++++++++++++- include/winternl.h | 1 + 2 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/tests/actctx.c b/dlls/kernel32/tests/actctx.c index fa67d37138c..469d75823f4 100644 --- a/dlls/kernel32/tests/actctx.c +++ b/dlls/kernel32/tests/actctx.c @@ -3848,8 +3848,31 @@ static void test_one_sxs_and_one_local_2(void) clean_sxs_info(&dll); }
+#define check_redirected_flag(a, b) _check_redirected_flag(__LINE__, a, b) +static void _check_redirected_flag(int line, HMODULE module, BOOL redirected) +{ + LIST_ENTRY *root = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; + BOOL found_dll = FALSE; + + 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 (mod->DllBase != module) + continue; + + if (redirected) + todo_wine + ok_(__FILE__, line)(mod->Flags & LDR_REDIRECTED, "Got unexpected flags %#lx.\n", mod->Flags); + else + ok_(__FILE__, line)(!(mod->Flags & LDR_REDIRECTED), "Got unexpected flags %#lx.\n", mod->Flags);
-/* Test if we can get a module handle from loaded normal dll while context is active */ + found_dll = TRUE; + } + ok(found_dll, "Couldn't find module %p in module list.\n", module); +} + +/* Test GetModuleHandleA() with DLL base names in different context states */ static void test_one_with_sxs_and_GetModuleHandleA(void) { sxs_info dll; @@ -3864,18 +3887,40 @@ static void test_one_with_sxs_and_GetModuleHandleA(void) extract_resource("dummy.dll", "TESTDLL", path_dll_local);
module = LoadLibraryA(path_dll_local); + check_redirected_flag(module, FALSE);
fill_sxs_info(&dll, "1", "dummy.dll", two_dll_manifest_exe, two_dll_manifest_dll, FALSE); success = ActivateActCtx(dll.handle_context, &dll.cookie); ok(success, "ActivateActCtx failed: %ld\n", GetLastError());
+ /* Loaded normal dll can't be found while context is active */ module_temp = GetModuleHandleA("sxs_dll.dll"); ok (module_temp == 0, "Expected 0, got %p\n", module_temp);
+ dll.module = LoadLibraryA("sxs_dll.dll"); + ok(dll.module != NULL && dll.module != module, "LoadLibrary failed\n"); + check_redirected_flag(dll.module, TRUE); + + /* Loaded SxS dll should be found while context is active */ + module_temp = GetModuleHandleA("sxs_dll.dll"); + ok(module_temp == dll.module, "Got unexpected module.\n"); + DeactivateActCtx(0, dll.cookie); + check_redirected_flag(dll.module, TRUE); + + /* Normal loaded dll should be found while context is inactive */ + module_temp = GetModuleHandleA("sxs_dll.dll"); + todo_wine + ok(module_temp == module, "Got unexpected module.\n");
if (module) FreeLibrary(module); + + /* Loaded SxS dll can't be found while context is inactive */ + module_temp = GetModuleHandleA("sxs_dll.dll"); + todo_wine + ok(module_temp == NULL, "Got unexpected module.\n"); + if (dll.module) FreeLibrary(dll.module); if (*path_dll_local) diff --git a/include/winternl.h b/include/winternl.h index a7ad7a9fa79..3377a418e0e 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -3947,6 +3947,7 @@ typedef void (CALLBACK *PLDR_DLL_NOTIFICATION_FUNCTION)(ULONG, LDR_DLL_NOTIFICAT #define LDR_PROCESS_ATTACHED 0x00080000 #define LDR_COR_IMAGE 0x00400000 #define LDR_COR_ILONLY 0x01000000 +#define LDR_REDIRECTED 0x10000000
/* these ones is Wine specific */ #define LDR_DONT_RESOLVE_REFS 0x40000000
From: Zhiyi Zhang zzhang@codeweavers.com
SxS DLLs are found via find_actctx_dll(). When activation contexts are inactive, GetModuleHandle() shouldn't find SxS DLLs with the same base name of a normal DLL. Whether a DLL is a SxS DLL is marked by the LDR_REDIRECTED(0x10000000) flag in LDR_DATA_TABLE_ENTRY.Flags. Manual testing also shows that LDR_REDIRECTED is not present for DLLs redirected via the API set mechanism. --- dlls/kernel32/tests/actctx.c | 3 --- dlls/ntdll/loader.c | 39 +++++++++++++++++++++++++----------- 2 files changed, 27 insertions(+), 15 deletions(-)
diff --git a/dlls/kernel32/tests/actctx.c b/dlls/kernel32/tests/actctx.c index 469d75823f4..1bdb6dd51f2 100644 --- a/dlls/kernel32/tests/actctx.c +++ b/dlls/kernel32/tests/actctx.c @@ -3862,7 +3862,6 @@ static void _check_redirected_flag(int line, HMODULE module, BOOL redirected) continue;
if (redirected) - todo_wine ok_(__FILE__, line)(mod->Flags & LDR_REDIRECTED, "Got unexpected flags %#lx.\n", mod->Flags); else ok_(__FILE__, line)(!(mod->Flags & LDR_REDIRECTED), "Got unexpected flags %#lx.\n", mod->Flags); @@ -3910,7 +3909,6 @@ static void test_one_with_sxs_and_GetModuleHandleA(void)
/* Normal loaded dll should be found while context is inactive */ module_temp = GetModuleHandleA("sxs_dll.dll"); - todo_wine ok(module_temp == module, "Got unexpected module.\n");
if (module) @@ -3918,7 +3916,6 @@ static void test_one_with_sxs_and_GetModuleHandleA(void)
/* Loaded SxS dll can't be found while context is inactive */ module_temp = GetModuleHandleA("sxs_dll.dll"); - todo_wine ok(module_temp == NULL, "Got unexpected module.\n");
if (dll.module) diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index b1a8544999c..c5c34935efd 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -600,14 +600,16 @@ static WINE_MODREF *find_basename_module( LPCWSTR name )
RtlInitUnicodeString( &name_str, name );
- if (cached_modref && RtlEqualUnicodeString( &name_str, &cached_modref->ldr.BaseDllName, TRUE )) + if (cached_modref && !(cached_modref->ldr.Flags & LDR_REDIRECTED) + && RtlEqualUnicodeString( &name_str, &cached_modref->ldr.BaseDllName, TRUE )) return cached_modref;
mark = &hash_table[hash_basename( &name_str )]; for (entry = mark->Flink; entry != mark; entry = entry->Flink) { WINE_MODREF *mod = CONTAINING_RECORD(entry, WINE_MODREF, ldr.HashLinks); - if (RtlEqualUnicodeString( &name_str, &mod->ldr.BaseDllName, TRUE ) && !mod->system) + if (!mod->system && !(mod->ldr.Flags & LDR_REDIRECTED) + && RtlEqualUnicodeString( &name_str, &mod->ldr.BaseDllName, TRUE )) { cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr); return cached_modref; @@ -2249,7 +2251,7 @@ done: */ static NTSTATUS build_module( LPCWSTR load_path, const UNICODE_STRING *nt_name, void **module, const SECTION_IMAGE_INFORMATION *image_info, const struct file_id *id, - DWORD flags, BOOL system, WINE_MODREF **pwm ) + DWORD flags, BOOL system, BOOL redirected, WINE_MODREF **pwm ) { static const char builtin_signature[] = "Wine builtin DLL"; char *signature = (char *)((IMAGE_DOS_HEADER *)*module + 1); @@ -2274,6 +2276,7 @@ static NTSTATUS build_module( LPCWSTR load_path, const UNICODE_STRING *nt_name, if (id) wm->id = *id; if (image_info->LoaderFlags) wm->ldr.Flags |= LDR_COR_IMAGE; if (image_info->ComPlusILOnly) wm->ldr.Flags |= LDR_COR_ILONLY; + if (redirected) wm->ldr.Flags |= LDR_REDIRECTED; wm->system = system;
update_load_config( *module ); @@ -2798,7 +2801,7 @@ static WINE_MODREF *find_existing_module( HMODULE module ) */ static NTSTATUS load_native_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name, HANDLE mapping, const SECTION_IMAGE_INFORMATION *image_info, const struct file_id *id, - DWORD flags, BOOL system, WINE_MODREF** pwm ) + DWORD flags, BOOL system, BOOL redirected, WINE_MODREF** pwm ) { void *module = NULL; SIZE_T len = 0; @@ -2820,7 +2823,8 @@ static NTSTATUS load_native_dll( LPCWSTR load_path, const UNICODE_STRING *nt_nam if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH && !convert_to_pe64( module, image_info )) status = STATUS_INVALID_IMAGE_FORMAT; #endif - if (NT_SUCCESS(status)) status = build_module( load_path, nt_name, &module, image_info, id, flags, system, pwm ); + if (NT_SUCCESS(status)) status = build_module( load_path, nt_name, &module, image_info, id, + flags, system, redirected, pwm ); if (status && module) NtUnmapViewOfSection( NtCurrentProcess(), module ); return status; } @@ -2855,7 +2859,8 @@ static NTSTATUS load_so_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name, { SECTION_IMAGE_INFORMATION image_info = { 0 };
- if ((status = build_module( load_path, ¶ms.nt_name, &module, &image_info, NULL, flags, FALSE, &wm ))) + if ((status = build_module( load_path, ¶ms.nt_name, &module, &image_info, NULL, flags, + FALSE, FALSE, &wm ))) { if (module) NtUnmapViewOfSection( NtCurrentProcess(), module ); return status; @@ -2895,7 +2900,8 @@ static WINE_MODREF *build_main_module(void) #endif status = RtlDosPathNameToNtPathName_U_WithStatus( params->ImagePathName.Buffer, &nt_name, NULL, NULL ); if (status) goto failed; - status = build_module( NULL, &nt_name, &module, &info, NULL, DONT_RESOLVE_DLL_REFERENCES, FALSE, &wm ); + status = build_module( NULL, &nt_name, &module, &info, NULL, DONT_RESOLVE_DLL_REFERENCES, FALSE, + FALSE, &wm ); if (status) goto failed; RtlFreeUnicodeString( &nt_name ); wm->ldr.LoadCount = -1; @@ -3249,13 +3255,14 @@ done: */ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, UNICODE_STRING *nt_name, WINE_MODREF **pwm, HANDLE *mapping, SECTION_IMAGE_INFORMATION *image_info, - struct file_id *id, BOOL find_loaded ) + struct file_id *id, BOOL *redirected, BOOL find_loaded ) { WCHAR *fullname = NULL; NTSTATUS status; ULONG wow64_old_value = 0;
*pwm = NULL; + *redirected = FALSE; nt_name->Buffer = NULL;
if (!contains_path( libname )) @@ -3263,7 +3270,11 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, UNI status = find_apiset_dll( libname, &fullname ); if (status == STATUS_DLL_NOT_FOUND) return status;
- if (status) status = find_actctx_dll( libname, &fullname ); + if (status) + { + status = find_actctx_dll( libname, &fullname ); + if (status == STATUS_SUCCESS) *redirected = TRUE; + }
if (status == STATUS_SUCCESS) { @@ -3316,6 +3327,7 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, DWORD fl HANDLE mapping = 0; SECTION_IMAGE_INFORMATION image_info; NTSTATUS nts = STATUS_DLL_NOT_FOUND; + BOOL redirected; void *prev;
TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) ); @@ -3325,7 +3337,8 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, DWORD fl
if (nts) { - nts = find_dll_file( load_path, libname, &nt_name, pwm, &mapping, &image_info, &id, FALSE ); + nts = find_dll_file( load_path, libname, &nt_name, pwm, &mapping, &image_info, &id, + &redirected, FALSE ); system = FALSE; }
@@ -3352,7 +3365,8 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, DWORD fl break;
case STATUS_SUCCESS: /* valid PE file */ - nts = load_native_dll( load_path, &nt_name, mapping, &image_info, &id, flags, system, pwm ); + nts = load_native_dll( load_path, &nt_name, mapping, &image_info, &id, flags, system, + redirected, pwm ); break; }
@@ -3493,6 +3507,7 @@ NTSTATUS WINAPI LdrGetDllHandleEx( ULONG flags, LPCWSTR load_path, ULONG *dll_ch SECTION_IMAGE_INFORMATION image_info; UNICODE_STRING nt_name; struct file_id id; + BOOL redirected; NTSTATUS status; WINE_MODREF *wm; WCHAR *dllname; @@ -3515,7 +3530,7 @@ NTSTATUS WINAPI LdrGetDllHandleEx( ULONG flags, LPCWSTR load_path, ULONG *dll_ch RtlEnterCriticalSection( &loader_section );
status = find_dll_file( load_path, dllname ? dllname : name->Buffer, - &nt_name, &wm, &mapping, &image_info, &id, TRUE ); + &nt_name, &wm, &mapping, &image_info, &id, &redirected, TRUE );
if (wm) *base = wm->ldr.DllBase; else
Nikolay Sivov (@nsivov) commented about dlls/kernel32/tests/actctx.c:
- BOOL found_dll = FALSE;
- 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 (mod->DllBase != module)continue;if (redirected)ok_(__FILE__, line)(mod->Flags & LDR_REDIRECTED, "Got unexpected flags %#lx.\n", mod->Flags);elseok_(__FILE__, line)(!(mod->Flags & LDR_REDIRECTED), "Got unexpected flags %#lx.\n", mod->Flags);found_dll = TRUE;- }
You could probably break out right here.