Merge branch 'fwdexp-refcount' into 'master'

ntdll: Properly track refcount with forwarded exports.

See merge request wine/wine!7
This commit is contained in:
Jinoh Kang 2024-11-19 19:13:34 +00:00
commit 5a4b03ccf8
2 changed files with 105 additions and 30 deletions

View file

@ -2775,7 +2775,6 @@ static void subtest_export_forwarder_dep_chain( size_t num_chained_export_module
/* FreeLibrary() should *not* unload the DLL immediately */ /* FreeLibrary() should *not* unload the DLL immediately */
module = GetModuleHandleA( temp_paths[i] ); module = GetModuleHandleA( temp_paths[i] );
todo_wine_if(i < ultimate_depender_index && i + 1 != importer_index)
ok( module == modules[i], "modules[%Iu] expected %p, got %p (unloaded?) err=%lu\n", ok( module == modules[i], "modules[%Iu] expected %p, got %p (unloaded?) err=%lu\n",
i, modules[i], module, GetLastError() ); i, modules[i], module, GetLastError() );
} }
@ -2787,7 +2786,6 @@ static void subtest_export_forwarder_dep_chain( size_t num_chained_export_module
{ {
HMODULE module = GetModuleHandleA( temp_paths[i] ); HMODULE module = GetModuleHandleA( temp_paths[i] );
todo_wine_if(i < ultimate_depender_index && i + 1 != importer_index)
ok( module == modules[i], "modules[%Iu] expected %p, got %p (unloaded?) err=%lu\n", ok( module == modules[i], "modules[%Iu] expected %p, got %p (unloaded?) err=%lu\n",
i, modules[i], module, GetLastError() ); i, modules[i], module, GetLastError() );
} }

View file

@ -184,9 +184,17 @@ static RTL_BITMAP tls_bitmap;
static RTL_BITMAP tls_expansion_bitmap; static RTL_BITMAP tls_expansion_bitmap;
static WINE_MODREF *cached_modref; static WINE_MODREF *cached_modref;
static WINE_MODREF *current_modref;
static WINE_MODREF *last_failed_modref; static WINE_MODREF *last_failed_modref;
struct importer
{
struct importer *prev;
WINE_MODREF *modref;
BOOL is_dynamic;
};
static struct importer *current_importer;
static LDR_DDAG_NODE *node_ntdll, *node_kernel32; static LDR_DDAG_NODE *node_ntdll, *node_kernel32;
static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, DWORD flags, WINE_MODREF** pwm, BOOL system ); static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, DWORD flags, WINE_MODREF** pwm, BOOL system );
@ -566,6 +574,35 @@ static ULONG_PTR allocate_stub( const char *dll, const char *name )
static inline ULONG_PTR allocate_stub( const char *dll, const char *name ) { return 0xdeadbeef; } static inline ULONG_PTR allocate_stub( const char *dll, const char *name ) { return 0xdeadbeef; }
#endif /* __i386__ */ #endif /* __i386__ */
/* The loader_section must be locked while calling this function. */
static void push_importer( struct importer *importer, WINE_MODREF *modref, BOOL is_dynamic )
{
importer->modref = modref;
importer->is_dynamic = is_dynamic;
importer->prev = current_importer;
current_importer = importer;
}
/* The loader_section must be locked while calling this function. */
static void pop_importer( struct importer *importer )
{
current_importer = importer->prev;
}
/* The loader_section must be locked while calling this function. */
static const WCHAR *get_last_static_importer_name(void)
{
struct importer *importer;
for (importer = current_importer; importer != NULL; importer = importer->prev)
{
if (!importer->is_dynamic)
{
return importer->modref->ldr.BaseDllName.Buffer;
}
}
return NULL;
}
/* call ldr notifications */ /* call ldr notifications */
static void call_ldr_notifications( ULONG reason, LDR_DATA_TABLE_ENTRY *module ) static void call_ldr_notifications( ULONG reason, LDR_DATA_TABLE_ENTRY *module )
{ {
@ -800,7 +837,7 @@ static NTSTATUS build_import_name( WCHAR buffer[256], const char *import, int le
{ {
const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap; const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap;
const API_SET_NAMESPACE_ENTRY *entry; const API_SET_NAMESPACE_ENTRY *entry;
const WCHAR *host = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL; const WCHAR *host = current_importer->modref->ldr.BaseDllName.Buffer;
UNICODE_STRING str; UNICODE_STRING str;
while (len && import[len-1] == ' ') len--; /* remove trailing spaces */ while (len && import[len-1] == ' ') len--; /* remove trailing spaces */
@ -900,6 +937,21 @@ static void remove_single_list_entry( LDRP_CSLIST *list, SINGLE_LIST_ENTRY *entr
entry->Next = NULL; entry->Next = NULL;
} }
static LDR_DEPENDENCY *find_module_dependency( LDR_DDAG_NODE *from, LDR_DDAG_NODE *to )
{
SINGLE_LIST_ENTRY *entry, *mark = from->Dependencies.Tail;
if (!mark) return NULL;
for (entry = mark->Next; entry != mark; entry = entry->Next)
{
LDR_DEPENDENCY *dep = CONTAINING_RECORD( entry, LDR_DEPENDENCY, dependency_to_entry );
if (dep->dependency_from == from && dep->dependency_to == to) return dep;
}
return NULL;
}
/********************************************************************** /**********************************************************************
* add_module_dependency_after * add_module_dependency_after
*/ */
@ -908,6 +960,15 @@ static BOOL add_module_dependency_after( LDR_DDAG_NODE *from, LDR_DDAG_NODE *to,
{ {
LDR_DEPENDENCY *dep; LDR_DEPENDENCY *dep;
if ((dep = find_module_dependency( from, to )))
{
/* Dependency already exists; consume the module reference stolen from the caller */
LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD( to->Modules.Flink, LDR_DATA_TABLE_ENTRY, NodeModuleLink );
WINE_MODREF *wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
LdrUnloadDll( wm->ldr.DllBase );
return TRUE;
}
if (!(dep = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*dep) ))) return FALSE; if (!(dep = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*dep) ))) return FALSE;
dep->dependency_from = from; dep->dependency_from = from;
@ -984,11 +1045,7 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS
if (load_dll( load_path, mod_name, 0, &wm, imp->system ) == STATUS_SUCCESS && if (load_dll( load_path, mod_name, 0, &wm, imp->system ) == STATUS_SUCCESS &&
!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
{ {
if (!imports_fixup_done && current_modref) if (imports_fixup_done && process_attach( wm->ldr.DdagNode, NULL ) != STATUS_SUCCESS)
{
add_module_dependency( current_modref->ldr.DdagNode, wm->ldr.DdagNode );
}
else if (process_attach( wm->ldr.DdagNode, NULL ) != STATUS_SUCCESS)
{ {
LdrUnloadDll( wm->ldr.DllBase ); LdrUnloadDll( wm->ldr.DllBase );
wm = NULL; wm = NULL;
@ -1002,6 +1059,11 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS
return NULL; return NULL;
} }
} }
else
{
if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
}
if ((exports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE, if ((exports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size ))) IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
{ {
@ -1021,6 +1083,12 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS
forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer), forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer),
debugstr_w(get_modref(module)->ldr.BaseDllName.Buffer) ); debugstr_w(get_modref(module)->ldr.BaseDllName.Buffer) );
} }
else if (wm->ldr.DdagNode != node_ntdll && wm->ldr.DdagNode != node_kernel32)
{
add_module_dependency( current_importer->modref->ldr.DdagNode, wm->ldr.DdagNode );
wm = NULL;
}
if (wm) LdrUnloadDll( wm->ldr.DllBase );
return proc; return proc;
} }
@ -1054,12 +1122,12 @@ static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY
if (TRACE_ON(snoop)) if (TRACE_ON(snoop))
{ {
const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL; const WCHAR *user = get_last_static_importer_name();
proc = SNOOP_GetProcAddress( module, exports, exp_size, proc, ordinal, user ); proc = SNOOP_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
} }
if (TRACE_ON(relay)) if (TRACE_ON(relay))
{ {
const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL; const WCHAR *user = get_last_static_importer_name();
proc = RELAY_GetProcAddress( module, exports, exp_size, proc, ordinal, user ); proc = RELAY_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
} }
return proc; return proc;
@ -1152,7 +1220,8 @@ void * WINAPI RtlFindExportedRoutineByName( HMODULE module, const char *name )
*/ */
static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path, WINE_MODREF **pwm ) static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path, WINE_MODREF **pwm )
{ {
BOOL system = current_modref->system || (current_modref->ldr.Flags & LDR_WINE_INTERNAL); struct importer *importer = current_importer;
BOOL system = importer->modref->system || (importer->modref->ldr.Flags & LDR_WINE_INTERNAL);
NTSTATUS status; NTSTATUS status;
WINE_MODREF *wmImp; WINE_MODREF *wmImp;
HMODULE imp_mod; HMODULE imp_mod;
@ -1187,10 +1256,10 @@ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LP
{ {
if (status == STATUS_DLL_NOT_FOUND) if (status == STATUS_DLL_NOT_FOUND)
ERR("Library %s (which is needed by %s) not found\n", ERR("Library %s (which is needed by %s) not found\n",
name, debugstr_w(current_modref->ldr.FullDllName.Buffer)); name, debugstr_w(importer->modref->ldr.FullDllName.Buffer));
else else
ERR("Loading library %s (which is needed by %s) failed (error %lx).\n", ERR("Loading library %s (which is needed by %s) failed (error %lx).\n",
name, debugstr_w(current_modref->ldr.FullDllName.Buffer), status); name, debugstr_w(importer->modref->ldr.FullDllName.Buffer), status);
return FALSE; return FALSE;
} }
@ -1223,7 +1292,7 @@ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LP
thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name ); thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
} }
WARN(" imported from %s, allocating stub %p\n", WARN(" imported from %s, allocating stub %p\n",
debugstr_w(current_modref->ldr.FullDllName.Buffer), debugstr_w(importer->modref->ldr.FullDllName.Buffer),
(void *)thunk_list->u1.Function ); (void *)thunk_list->u1.Function );
import_list++; import_list++;
thunk_list++; thunk_list++;
@ -1243,7 +1312,7 @@ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LP
{ {
thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) ); thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
WARN("No implementation for %s.%d imported from %s, setting to %p\n", WARN("No implementation for %s.%d imported from %s, setting to %p\n",
name, ordinal, debugstr_w(current_modref->ldr.FullDllName.Buffer), name, ordinal, debugstr_w(importer->modref->ldr.FullDllName.Buffer),
(void *)thunk_list->u1.Function ); (void *)thunk_list->u1.Function );
} }
TRACE_(imports)("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function ); TRACE_(imports)("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );
@ -1259,7 +1328,7 @@ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LP
{ {
thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name ); thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
WARN("No implementation for %s.%s imported from %s, setting to %p\n", WARN("No implementation for %s.%s imported from %s, setting to %p\n",
name, pe_name->Name, debugstr_w(current_modref->ldr.FullDllName.Buffer), name, pe_name->Name, debugstr_w(importer->modref->ldr.FullDllName.Buffer),
(void *)thunk_list->u1.Function ); (void *)thunk_list->u1.Function );
} }
TRACE_(imports)("--- %s %s.%d = %p\n", TRACE_(imports)("--- %s %s.%d = %p\n",
@ -1458,21 +1527,21 @@ static void free_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
*/ */
static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void **entry ) static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void **entry )
{ {
struct importer importer;
NTSTATUS status; NTSTATUS status;
void *proc; void *proc;
const char *name; const char *name;
WINE_MODREF *prev, *imp; WINE_MODREF *imp;
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;
prev = current_modref; push_importer( &importer, wm, FALSE );
current_modref = wm;
assert( !wm->ldr.DdagNode->Dependencies.Tail ); assert( !wm->ldr.DdagNode->Dependencies.Tail );
if (!(status = load_dll( load_path, L"mscoree.dll", 0, &imp, FALSE )) if (!(status = load_dll( load_path, L"mscoree.dll", 0, &imp, FALSE ))
&& !add_module_dependency_after( wm->ldr.DdagNode, imp->ldr.DdagNode, NULL )) && !add_module_dependency_after( wm->ldr.DdagNode, imp->ldr.DdagNode, NULL ))
status = STATUS_NO_MEMORY; status = STATUS_NO_MEMORY;
current_modref = prev; pop_importer( &importer );
if (status) if (status)
{ {
ERR( "mscoree.dll not found, IL-only binary %s cannot be loaded\n", ERR( "mscoree.dll not found, IL-only binary %s cannot be loaded\n",
@ -1499,7 +1568,8 @@ static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
{ {
const IMAGE_IMPORT_DESCRIPTOR *imports; const IMAGE_IMPORT_DESCRIPTOR *imports;
SINGLE_LIST_ENTRY *dep_after; SINGLE_LIST_ENTRY *dep_after;
WINE_MODREF *prev, *imp; struct importer importer;
WINE_MODREF *imp;
int i, nb_imports; int i, nb_imports;
DWORD size; DWORD size;
NTSTATUS status; NTSTATUS status;
@ -1525,8 +1595,7 @@ static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
/* load the imported modules. They are automatically /* load the imported modules. They are automatically
* added to the modref list of the process. * added to the modref list of the process.
*/ */
prev = current_modref; push_importer( &importer, wm, FALSE );
current_modref = wm;
status = STATUS_SUCCESS; status = STATUS_SUCCESS;
for (i = 0; i < nb_imports; i++) for (i = 0; i < nb_imports; i++)
{ {
@ -1536,7 +1605,7 @@ static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
else if (imp && imp->ldr.DdagNode != node_ntdll && imp->ldr.DdagNode != node_kernel32) else if (imp && imp->ldr.DdagNode != node_ntdll && imp->ldr.DdagNode != node_kernel32)
add_module_dependency_after( wm->ldr.DdagNode, imp->ldr.DdagNode, dep_after ); add_module_dependency_after( wm->ldr.DdagNode, imp->ldr.DdagNode, dep_after );
} }
current_modref = prev; pop_importer( &importer );
if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie ); if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
return status; return status;
} }
@ -1817,8 +1886,9 @@ static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved )
/* Call DLL entry point */ /* Call DLL entry point */
if (status == STATUS_SUCCESS) if (status == STATUS_SUCCESS)
{ {
WINE_MODREF *prev = current_modref; struct importer importer;
current_modref = wm;
push_importer( &importer, wm, FALSE );
call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_LOADED, &wm->ldr ); call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_LOADED, &wm->ldr );
status = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved ); status = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
@ -1835,7 +1905,8 @@ static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved )
last_failed_modref = wm; last_failed_modref = wm;
WARN("Initialization of %s failed\n", debugstr_w(wm->ldr.BaseDllName.Buffer)); WARN("Initialization of %s failed\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
} }
current_modref = prev;
pop_importer( &importer );
} }
if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie ); if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
@ -2101,8 +2172,14 @@ NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name,
else if ((exports = RtlImageDirectoryEntryToData( module, TRUE, else if ((exports = RtlImageDirectoryEntryToData( module, TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size ))) IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
{ {
void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, NULL ) struct importer importer;
: find_ordinal_export( module, exports, exp_size, ord - exports->Base, NULL ); void *proc;
push_importer( &importer, wm, TRUE );
proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, NULL )
: find_ordinal_export( module, exports, exp_size, ord - exports->Base, NULL );
pop_importer( &importer );
if (proc) if (proc)
{ {
*address = proc; *address = proc;