Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntdll/loader.c | 371 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 293 insertions(+), 78 deletions(-)
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index ff5a175027c..2ccc3b1d30e 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -132,6 +132,7 @@ typedef struct _wine_modref int alloc_deps; int nDeps; struct _wine_modref **deps; + RTL_CRITICAL_SECTION module_section; } WINE_MODREF;
static UINT tls_module_count; /* number of modules with TLS directory */ @@ -147,6 +148,30 @@ static RTL_CRITICAL_SECTION_DEBUG critsect_debug = }; static RTL_CRITICAL_SECTION loader_section = { &critsect_debug, -1, 0, 0, 0, 0 };
+/* ldr_data_section allows for read only access to module linked lists in PEB and + * the underlying structures without taking loader lock. The relations between + * ldr_data_section, loader_section and module_section from WINE_MODREF are: + * - modification to the module linked lists is done with both ldr_data_ and loader_ + * sections locked; + * - read only access to loader linked lists is allowed with either loader_ or ldr_data_ + * section locked; + * - the WINE_MODREF pointer (and the underlying module mapping) should stay valid + * while any of three locks is held; if loader_ or ldr_data_ section is held module_section + * can be unlocked and locked again without the risk of loosing the module reference; + * - query or modification if WINE_MODREF must be done with module_section locked, except for + * reading the fields initialized on module reference creation which don't change after + * (those can be accessed whenever module reference is valid); + * - the order of locking is: loader_section, ldr_data_section, module_section; + * - thread should not have any module_section locked when requesting loader_ or ldr_data_ lock. */ +static CRITICAL_SECTION ldr_data_section; +static CRITICAL_SECTION_DEBUG ldr_data_section_debug = +{ + 0, 0, &ldr_data_section, + { &ldr_data_section_debug.ProcessLocksList, &ldr_data_section_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": ldr_data_section") } +}; +static CRITICAL_SECTION ldr_data_section = { &ldr_data_section_debug, -1, 0, 0, 0, 0 }; + static CRITICAL_SECTION dlldir_section; static CRITICAL_SECTION_DEBUG dlldir_critsect_debug = { @@ -176,11 +201,23 @@ static WINE_MODREF *last_failed_modref; static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext, DWORD flags, WINE_MODREF** pwm ); static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved ); -static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports, +static FARPROC find_ordinal_export( WINE_MODREF **wm, const IMAGE_EXPORT_DIRECTORY *exports, DWORD exp_size, DWORD ordinal, LPCWSTR load_path ); -static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports, +static FARPROC find_named_export( WINE_MODREF **wm, const IMAGE_EXPORT_DIRECTORY *exports, DWORD exp_size, const char *name, int hint, LPCWSTR load_path );
+static void lock_ldr_data( BOOL lock_always ) +{ + if (lock_always || !RtlIsCriticalSectionLockedByThread( &loader_section )) + RtlEnterCriticalSection( &ldr_data_section ); +} + +static void unlock_ldr_data( BOOL unlock_always ) +{ + if (unlock_always || !RtlIsCriticalSectionLockedByThread( &loader_section )) + RtlLeaveCriticalSection( &ldr_data_section ); +} + /* convert PE image VirtualAddress to Real Address */ static inline void *get_rva( HMODULE module, DWORD va ) { @@ -462,27 +499,65 @@ static void call_ldr_notifications( ULONG reason, LDR_DATA_TABLE_ENTRY *module ) } }
+ +/************************************************************************* + * lock_modref + * + * Locks module reference. + */ +static void lock_modref( WINE_MODREF *modref ) +{ + RtlEnterCriticalSection( &modref->module_section ); +} + + +/************************************************************************* + * unlock_modref + * + * Unlocks module reference. + */ +static void unlock_modref( WINE_MODREF *modref ) +{ + assert(modref && RtlIsCriticalSectionLockedByThread( &modref->module_section )); + RtlLeaveCriticalSection( &modref->module_section ); +} + + /************************************************************************* * get_modref * * Looks for the referenced HMODULE in the current process - * The loader_section must be locked while calling this function. */ static WINE_MODREF *get_modref( HMODULE hmod ) { PLIST_ENTRY mark, entry; PLDR_DATA_TABLE_ENTRY mod; + WINE_MODREF *ret = NULL; + + lock_ldr_data( FALSE );
- if (cached_modref && cached_modref->ldr.DllBase == hmod) return cached_modref; + if (cached_modref && cached_modref->ldr.DllBase == hmod) + { + ret = cached_modref; + goto done; + }
mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList; for (entry = mark->Flink; entry != mark; entry = entry->Flink) { mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); if (mod->DllBase == hmod) - return cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr); + { + ret = cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr); + break; + } } - return NULL; + +done: + if (ret) + lock_modref(ret); + unlock_ldr_data( FALSE ); + return ret; }
@@ -490,17 +565,22 @@ static WINE_MODREF *get_modref( HMODULE hmod ) * find_basename_module * * Find a module from its base name. - * The loader_section must be locked while calling this function */ static WINE_MODREF *find_basename_module( LPCWSTR name ) { PLIST_ENTRY mark, entry; UNICODE_STRING name_str; + WINE_MODREF *ret = NULL;
RtlInitUnicodeString( &name_str, name );
+ lock_ldr_data( FALSE ); + if (cached_modref && RtlEqualUnicodeString( &name_str, &cached_modref->ldr.BaseDllName, TRUE )) - return cached_modref; + { + ret = cached_modref; + goto done; + }
mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; for (entry = mark->Flink; entry != mark; entry = entry->Flink) @@ -508,11 +588,16 @@ static WINE_MODREF *find_basename_module( LPCWSTR name ) LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); if (RtlEqualUnicodeString( &name_str, &mod->BaseDllName, TRUE )) { - cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr); - return cached_modref; + ret = cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr); + break; } } - return NULL; + +done: + if (ret) + lock_modref(ret); + unlock_ldr_data( FALSE ); + return ret; }
@@ -520,31 +605,39 @@ static WINE_MODREF *find_basename_module( LPCWSTR name ) * find_fullname_module * * Find a module from its full path name. - * The loader_section must be locked while calling this function */ static WINE_MODREF *find_fullname_module( const UNICODE_STRING *nt_name ) { PLIST_ENTRY mark, entry; UNICODE_STRING name = *nt_name; + WINE_MODREF *ret = NULL;
if (name.Length <= 4 * sizeof(WCHAR)) return NULL; name.Length -= 4 * sizeof(WCHAR); /* for ??\ prefix */ name.Buffer += 4;
- if (cached_modref && RtlEqualUnicodeString( &name, &cached_modref->ldr.FullDllName, TRUE )) - return cached_modref; + lock_ldr_data( FALSE );
+ if (cached_modref && RtlEqualUnicodeString( &name, &cached_modref->ldr.FullDllName, TRUE )) + { + ret = cached_modref; + goto done; + } mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; for (entry = mark->Flink; entry != mark; entry = entry->Flink) { LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); if (RtlEqualUnicodeString( &name, &mod->FullDllName, TRUE )) { - cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr); - return cached_modref; + ret = cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr); + break; } } - return NULL; +done: + if (ret) + lock_modref(ret); + unlock_ldr_data( FALSE ); + return ret; }
@@ -552,13 +645,19 @@ static WINE_MODREF *find_fullname_module( const UNICODE_STRING *nt_name ) * find_fileid_module * * Find a module from its file id. - * The loader_section must be locked while calling this function */ static WINE_MODREF *find_fileid_module( const struct file_id *id ) { LIST_ENTRY *mark, *entry; + WINE_MODREF *ret = NULL;
- if (cached_modref && !memcmp( &cached_modref->id, id, sizeof(*id) )) return cached_modref; + lock_ldr_data( FALSE ); + + if (cached_modref && !memcmp( &cached_modref->id, id, sizeof(*id) )) + { + ret = cached_modref; + goto done; + }
mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; for (entry = mark->Flink; entry != mark; entry = entry->Flink) @@ -568,11 +667,15 @@ static WINE_MODREF *find_fileid_module( const struct file_id *id )
if (!memcmp( &wm->id, id, sizeof(*id) )) { - cached_modref = wm; - return wm; + ret = cached_modref = wm; + break; } } - return NULL; +done: + if (ret) + lock_modref(ret); + unlock_ldr_data( FALSE ); + return ret; }
@@ -603,29 +706,39 @@ static WINE_MODREF **grow_module_deps( WINE_MODREF *wm, int count ) * Find the final function pointer for a forwarded function. * The loader_section must be locked while calling this function. */ -static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path ) +static FARPROC find_forwarded_export( WINE_MODREF **wm_imp, const char *forward, LPCWSTR load_path ) { + HMODULE module = (*wm_imp)->ldr.DllBase; const IMAGE_EXPORT_DIRECTORY *exports; DWORD exp_size; WINE_MODREF *wm; - WCHAR buffer[32], *mod_name = buffer; + SIZE_T modname_size; + WCHAR *mod_name; + void *buffer; const char *end = strrchr(forward, '.'); FARPROC proc = NULL; + char *name;
if (!end) return NULL; - if ((end - forward) * sizeof(WCHAR) > sizeof(buffer) - sizeof(dllW)) - { - if (!(mod_name = RtlAllocateHeap( GetProcessHeap(), 0, (end - forward + sizeof(dllW)) * sizeof(WCHAR) ))) - return NULL; - } + + modname_size = (end - forward + sizeof(dllW)) * sizeof(WCHAR); + if (!(mod_name = buffer = RtlAllocateHeap( GetProcessHeap(), 0, modname_size + strlen( end + 1 ) + 1 ))) + return NULL; + name = (char *)buffer + modname_size; + ascii_to_unicode( mod_name, forward, end - forward ); mod_name[end - forward] = 0; if (!wcschr( mod_name, '.' )) memcpy( mod_name + (end - forward), dllW, sizeof(dllW) );
+ strcpy( name, end + 1 ); + + TRACE( "loading %s for '%s' used by '%s'\n", debugstr_w(mod_name), forward, + debugstr_w((*wm_imp)->ldr.FullDllName.Buffer) ); + unlock_modref( *wm_imp ); if (!(wm = find_basename_module( mod_name ))) { - TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward ); + TRACE( "delay loading %s.\n", debugstr_w(mod_name) ); if (load_dll( load_path, mod_name, dllW, 0, &wm ) == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) { @@ -636,37 +749,36 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS } else if (process_attach( wm, NULL ) != STATUS_SUCCESS) { - LdrUnloadDll( wm->ldr.DllBase ); + void *dllbase = wm->ldr.DllBase; + + unlock_modref( wm ); wm = NULL; + LdrUnloadDll( dllbase ); } } - if (!wm) { - if (mod_name != buffer) RtlFreeHeap( GetProcessHeap(), 0, mod_name ); - ERR( "module not found for forward '%s' used by %s\n", - forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer) ); - return NULL; + ERR( "module not found, mod_name %s, path %s.\n", debugstr_w(mod_name), debugstr_w(load_path) ); + goto done; } } if ((exports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size ))) { - const char *name = end + 1; if (*name == '#') /* ordinal */ - proc = find_ordinal_export( wm->ldr.DllBase, exports, exp_size, atoi(name+1), load_path ); + proc = find_ordinal_export( &wm, exports, exp_size, atoi(name+1), load_path ); else - proc = find_named_export( wm->ldr.DllBase, exports, exp_size, name, -1, load_path ); + proc = find_named_export( &wm, exports, exp_size, name, -1, load_path ); }
+ if (wm) + unlock_modref(wm); + if (!proc) - { - ERR("function not found for forward '%s' used by %s." - " If you are using builtin %s, try using the native one instead.\n", - forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer), - debugstr_w(get_modref(module)->ldr.BaseDllName.Buffer) ); - } - if (mod_name != buffer) RtlFreeHeap( GetProcessHeap(), 0, mod_name ); + ERR( "function not found for forward '%s.%s'.", debugstr_w(mod_name), debugstr_a(name) ); +done: + RtlFreeHeap( GetProcessHeap(), 0, buffer ); + *wm_imp = get_modref( module ); return proc; }
@@ -676,11 +788,11 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS * * Find an exported function by ordinal. * The exports base must have been subtracted from the ordinal already. - * The loader_section must be locked while calling this function. */ -static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports, +static FARPROC find_ordinal_export( WINE_MODREF **wm, const IMAGE_EXPORT_DIRECTORY *exports, DWORD exp_size, DWORD ordinal, LPCWSTR load_path ) { + HMODULE module = (*wm)->ldr.DllBase; FARPROC proc; const DWORD *functions = get_rva( module, exports->AddressOfFunctions );
@@ -696,16 +808,18 @@ static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY /* if the address falls into the export dir, it's a forward */ if (((const char *)proc >= (const char *)exports) && ((const char *)proc < (const char *)exports + exp_size)) - return find_forwarded_export( module, (const char *)proc, load_path ); + return find_forwarded_export( wm, (const char *)proc, load_path );
if (TRACE_ON(snoop)) { - const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL; + const WCHAR *user = RtlIsCriticalSectionLockedByThread( &loader_section ) && current_modref + ? current_modref->ldr.BaseDllName.Buffer : NULL; proc = SNOOP_GetProcAddress( module, exports, exp_size, proc, ordinal, user ); } if (TRACE_ON(relay)) { - const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL; + const WCHAR *user = RtlIsCriticalSectionLockedByThread( &loader_section ) && current_modref + ? current_modref->ldr.BaseDllName.Buffer : NULL; proc = RELAY_GetProcAddress( module, exports, exp_size, proc, ordinal, user ); } return proc; @@ -716,11 +830,11 @@ static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY * find_named_export * * Find an exported function by name. - * The loader_section must be locked while calling this function. */ -static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports, +static FARPROC find_named_export( WINE_MODREF **wm, const IMAGE_EXPORT_DIRECTORY *exports, DWORD exp_size, const char *name, int hint, LPCWSTR load_path ) { + HMODULE module = (*wm)->ldr.DllBase; const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals ); const DWORD *names = get_rva( module, exports->AddressOfNames ); int min = 0, max = exports->NumberOfNames - 1; @@ -730,7 +844,7 @@ static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY * { char *ename = get_rva( module, names[hint] ); if (!strcmp( ename, name )) - return find_ordinal_export( module, exports, exp_size, ordinals[hint], load_path ); + return find_ordinal_export( wm, exports, exp_size, ordinals[hint], load_path ); }
/* then do a binary search */ @@ -739,7 +853,7 @@ static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY * int res, pos = (min + max) / 2; char *ename = get_rva( module, names[pos] ); if (!(res = strcmp( ename, name ))) - return find_ordinal_export( module, exports, exp_size, ordinals[pos], load_path ); + return find_ordinal_export( wm, exports, exp_size, ordinals[pos], load_path ); if (res > 0) max = pos - 1; else min = pos + 1; } @@ -754,8 +868,9 @@ static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY * * Import the dll specified by the given import descriptor. * The loader_section must be locked while calling this function. */ -static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path, WINE_MODREF **pwm ) +static BOOL import_dll( WINE_MODREF *wm, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path, WINE_MODREF **pwm ) { + HMODULE module = wm->ldr.DllBase; NTSTATUS status; WINE_MODREF *wmImp; HMODULE imp_mod; @@ -783,6 +898,8 @@ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LP return TRUE; }
+ unlock_modref( wm ); + while (len && name[len-1] == ' ') len--; /* remove trailing spaces */
if (len * sizeof(WCHAR) < sizeof(buffer)) @@ -794,7 +911,11 @@ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LP else /* need to allocate a larger buffer */ { WCHAR *ptr = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ); - if (!ptr) return FALSE; + if (!ptr) + { + lock_modref( wm ); + return FALSE; + } ascii_to_unicode( ptr, name, len ); ptr[len] = 0; status = load_dll( load_path, ptr, dllW, 0, &wmImp ); @@ -809,6 +930,7 @@ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LP else ERR("Loading library %s (which is needed by %s) failed (error %x).\n", name, debugstr_w(current_modref->ldr.FullDllName.Buffer), status); + lock_modref( wm ); return FALSE; }
@@ -855,8 +977,9 @@ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LP { int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
- thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size, + thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( &wmImp, exports, exp_size, ordinal - exports->Base, load_path ); + assert( wmImp ); if (!thunk_list->u1.Function) { thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) ); @@ -870,9 +993,10 @@ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LP { IMAGE_IMPORT_BY_NAME *pe_name; pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData ); - thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size, + thunk_list->u1.Function = (ULONG_PTR)find_named_export( &wmImp, exports, exp_size, (const char*)pe_name->Name, pe_name->Hint, load_path ); + assert( wmImp ); if (!thunk_list->u1.Function) { thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name ); @@ -891,6 +1015,7 @@ done: /* restore old protection of the import address table */ NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, &protect_old ); *pwm = wmImp; + lock_modref(wm); return TRUE; }
@@ -1082,12 +1207,16 @@ static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void *
prev = current_modref; current_modref = wm; - if (!(status = load_dll( load_path, mscoreeW, NULL, 0, &imp ))) wm->deps[0] = imp; + unlock_modref( wm ); + if (!(status = load_dll( load_path, mscoreeW, NULL, 0, &imp ))) + wm->deps[0] = imp; + current_modref = prev; if (status) { ERR( "mscoree.dll not found, IL-only binary %s cannot be loaded\n", debugstr_w(wm->ldr.BaseDllName.Buffer) ); + lock_modref( wm ); return status; }
@@ -1097,8 +1226,12 @@ static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void * IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size ))) { const char *name = (wm->ldr.Flags & LDR_IMAGE_IS_DLL) ? "_CorDllMain" : "_CorExeMain"; - proc = find_named_export( imp->ldr.DllBase, exports, exp_size, name, -1, load_path ); + proc = find_named_export( &imp, exports, exp_size, name, -1, load_path ); + assert( imp ); } + unlock_modref( imp ); + lock_modref( wm ); + if (!proc) return STATUS_PROCEDURE_NOT_FOUND; *entry = proc; return STATUS_SUCCESS; @@ -1148,12 +1281,13 @@ static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path ) { dep = wm->nDeps++;
- if (!import_dll( wm->ldr.DllBase, &imports[i], load_path, &imp )) + if (!import_dll( wm, &imports[i], load_path, &imp )) { imp = NULL; status = STATUS_DLL_NOT_FOUND; } wm->deps[dep] = imp; + unlock_modref( imp ); } current_modref = prev; if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie ); @@ -1181,6 +1315,8 @@ static WINE_MODREF *alloc_module( HMODULE hModule, const UNICODE_STRING *nt_name wm->ldr.Flags = LDR_DONT_RESOLVE_REFS | (builtin ? LDR_WINE_INTERNAL : 0); wm->ldr.TlsIndex = -1; wm->ldr.LoadCount = 1; + RtlInitializeCriticalSection( &wm->module_section ); + wm->module_section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": module_section");
if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, nt_name->Length - 3 * sizeof(WCHAR) ))) { @@ -1202,11 +1338,14 @@ static WINE_MODREF *alloc_module( HMODULE hModule, const UNICODE_STRING *nt_name wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint; }
+ lock_ldr_data( TRUE ); InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList, &wm->ldr.InLoadOrderLinks); InsertTailList(&NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList, &wm->ldr.InMemoryOrderLinks); /* wait until init is called for inserting into InInitializationOrderModuleList */ + lock_modref( wm ); + unlock_ldr_data( TRUE );
if (!(nt->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT)) { @@ -1405,19 +1544,28 @@ static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved ) if (lpReserved) wm->ldr.LoadCount = -1; /* pin it if imported by the main exe */ if (wm->ldr.ActivationContext) RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
+ unlock_modref( wm ); /* Recursively attach all DLLs this one depends on */ for ( i = 0; i < wm->nDeps; i++ ) { if (!wm->deps[i]) continue; - if ((status = process_attach( wm->deps[i], lpReserved )) != STATUS_SUCCESS) break; + + lock_modref( wm->deps[i] ); + status = process_attach( wm->deps[i], lpReserved ); + unlock_modref( wm->deps[i] ); + if (status != STATUS_SUCCESS) break; }
if (!wm->ldr.InInitializationOrderLinks.Flink) + { + lock_ldr_data( TRUE ); InsertTailList(&NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList, &wm->ldr.InInitializationOrderLinks); + unlock_ldr_data( TRUE ); + }
/* Call DLL entry point */ - if (status == STATUS_SUCCESS) + if (!status) { WINE_MODREF *prev = current_modref; current_modref = wm; @@ -1426,6 +1574,7 @@ static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved ) status = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved ); if (status == STATUS_SUCCESS) { + lock_modref( wm ); wm->ldr.Flags |= LDR_PROCESS_ATTACHED; } else @@ -1439,6 +1588,8 @@ static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved ) } current_modref = prev; } + if (status) + lock_modref( wm );
if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie ); /* Remove recursion flag */ @@ -1465,12 +1616,16 @@ static void attach_implicitly_loaded_dlls( LPVOID reserved ) for (entry = mark->Flink; entry != mark; entry = entry->Flink) { LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + WINE_MODREF *wm;
if (!(mod->Flags & LDR_IMAGE_IS_DLL)) continue; if (mod->Flags & (LDR_LOAD_IN_PROGRESS | LDR_PROCESS_ATTACHED)) continue; TRACE( "found implicitly loaded %s, attaching to it\n", debugstr_w(mod->BaseDllName.Buffer)); - process_attach( CONTAINING_RECORD(mod, WINE_MODREF, ldr), reserved ); + wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr); + lock_modref( wm ); + process_attach( wm, reserved ); + unlock_modref( wm ); break; /* restart the search from the start */ } if (entry == mark) break; /* nothing found */ @@ -1488,6 +1643,7 @@ static void process_detach(void) { PLIST_ENTRY mark, entry; PLDR_DATA_TABLE_ENTRY mod; + WINE_MODREF *wm;
mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList; do @@ -1502,10 +1658,12 @@ static void process_detach(void) if ( mod->LoadCount && !process_detaching ) continue;
+ wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr); + lock_modref( wm ); /* Call detach notification */ mod->Flags &= ~LDR_PROCESS_ATTACHED; - MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), - DLL_PROCESS_DETACH, ULongToPtr(process_detaching) ); + unlock_modref( wm ); + MODULE_InitDLL( wm, DLL_PROCESS_DETACH, ULongToPtr(process_detaching) ); call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_UNLOADED, mod );
/* Restart at head of WINE_MODREF list, as entries might have @@ -1557,6 +1715,7 @@ NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule) ret = STATUS_DLL_NOT_FOUND; else wm->ldr.Flags |= LDR_NO_DLL_CALLS; + unlock_modref( wm );
RtlLeaveCriticalSection( &loader_section );
@@ -1721,17 +1880,18 @@ NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name, IMAGE_EXPORT_DIRECTORY *exports; DWORD exp_size; NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND; + WINE_MODREF *modref;
RtlEnterCriticalSection( &loader_section );
/* check if the module itself is invalid to return the proper error */ - if (!get_modref( module )) ret = STATUS_DLL_NOT_FOUND; + if (!(modref = get_modref( module ))) ret = STATUS_DLL_NOT_FOUND; else if ((exports = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size ))) { LPCWSTR load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer; - void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, load_path ) - : find_ordinal_export( module, exports, exp_size, ord - exports->Base, load_path ); + void *proc = name ? find_named_export( &modref, exports, exp_size, name->Buffer, -1, load_path ) + : find_ordinal_export( &modref, exports, exp_size, ord - exports->Base, load_path ); if (proc) { *address = proc; @@ -1739,6 +1899,9 @@ NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name, } }
+ if (modref) + unlock_modref( modref ); + RtlLeaveCriticalSection( &loader_section ); return ret; } @@ -1911,8 +2074,11 @@ static NTSTATUS build_module( LPCWSTR load_path, const UNICODE_STRING *nt_name, if (status != STATUS_SUCCESS) { /* the module has only be inserted in the load & memory order lists */ + unlock_modref( wm ); + lock_ldr_data( TRUE ); RemoveEntryList(&wm->ldr.InLoadOrderLinks); RemoveEntryList(&wm->ldr.InMemoryOrderLinks); + unlock_ldr_data( TRUE );
/* FIXME: there are several more dangling references * left. Including dlls loaded by this dll before the @@ -2656,6 +2822,8 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WC
main_exe = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress ); loadorder = get_load_order( main_exe ? main_exe->ldr.BaseDllName.Buffer : NULL, &nt_name ); + if (main_exe) + unlock_modref( main_exe );
switch (nts) { @@ -2714,6 +2882,7 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WC { /* stub-only dll, try native */ TRACE( "%s pre-attach returned FALSE, preferring native\n", debugstr_us(&nt_name) ); + unlock_modref( *pwm ); LdrUnloadDll( (*pwm)->ldr.DllBase ); nts = STATUS_DLL_NOT_FOUND; /* map the dll again if it was unmapped */ @@ -2773,6 +2942,7 @@ NTSTATUS __cdecl __wine_init_unix_lib( HMODULE module, DWORD reason, const void if ((wm = get_modref( module ))) { NTSTATUS (CDECL *init_func)( HMODULE, DWORD, const void *, void * ) = wm->unix_entry; + unlock_modref( wm ); if (init_func) ret = init_func( module, reason, ptr_in, ptr_out ); } else ret = STATUS_INVALID_HANDLE; @@ -2801,11 +2971,20 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH LdrLoadDll(LPCWSTR path_name, DWORD flags, nts = process_attach( wm, NULL ); if (nts != STATUS_SUCCESS) { + unlock_modref( wm ); LdrUnloadDll(wm->ldr.DllBase); wm = NULL; } } - *hModule = (wm) ? wm->ldr.DllBase : NULL; + if (wm) + { + *hModule = wm->ldr.DllBase; + unlock_modref( wm ); + } + else + { + *hModule = NULL; + }
RtlLeaveCriticalSection( &loader_section ); return nts; @@ -2830,7 +3009,11 @@ NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_S
status = find_dll_file( load_path, name->Buffer, dllW, &nt_name, &wm, &module, &image_info, &id );
- if (wm) *base = wm->ldr.DllBase; + if (wm) + { + *base = wm->ldr.DllBase; + unlock_modref( wm ); + } else { if (status == STATUS_SUCCESS) NtUnmapViewOfSection( NtCurrentProcess(), module ); @@ -2863,6 +3046,7 @@ NTSTATUS WINAPI LdrAddRefDll( ULONG flags, HMODULE module ) else if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++; TRACE( "(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount ); + unlock_modref( wm ); } else ret = STATUS_INVALID_PARAMETER;
@@ -3239,6 +3423,7 @@ void WINAPI LdrShutdownThread(void)
RtlEnterCriticalSection( &loader_section ); wm = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress ); + unlock_modref( wm );
mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList; for (entry = mark->Blink; entry != mark; entry = entry->Blink) @@ -3283,6 +3468,7 @@ static void free_modref( WINE_MODREF *wm ) RemoveEntryList(&wm->ldr.InMemoryOrderLinks); if (wm->ldr.InInitializationOrderLinks.Flink) RemoveEntryList(&wm->ldr.InInitializationOrderLinks); + if (cached_modref == wm) cached_modref = NULL;
TRACE(" unloading %s\n", debugstr_w(wm->ldr.FullDllName.Buffer)); if (!TRACE_ON(module)) @@ -3297,11 +3483,15 @@ static void free_modref( WINE_MODREF *wm ) } SERVER_END_REQ;
+ unlock_modref( wm ); + + wm->module_section.DebugInfo->Spare[0] = 0; + RtlDeleteCriticalSection( &wm->module_section ); + free_tls_slot( &wm->ldr ); RtlReleaseActivationContext( wm->ldr.ActivationContext ); unix_funcs->unload_builtin_dll( wm->ldr.DllBase ); NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.DllBase ); - if (cached_modref == wm) cached_modref = NULL; RtlFreeUnicodeString( &wm->ldr.FullDllName ); RtlFreeHeap( GetProcessHeap(), 0, wm->deps ); RtlFreeHeap( GetProcessHeap(), 0, wm ); @@ -3321,13 +3511,18 @@ static void MODULE_FlushModrefs(void) LDR_DATA_TABLE_ENTRY *mod; WINE_MODREF*wm;
+ lock_ldr_data( TRUE ); mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList; for (entry = mark->Blink; entry != mark; entry = prev) { mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks); wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr); + lock_modref( wm ); prev = entry->Blink; - if (!mod->LoadCount) free_modref( wm ); + if (!mod->LoadCount) + free_modref( wm ); + else + unlock_modref( wm ); }
/* check load order list too for modules that haven't been initialized yet */ @@ -3336,9 +3531,14 @@ static void MODULE_FlushModrefs(void) { mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr); + lock_modref( wm ); prev = entry->Blink; - if (!mod->LoadCount) free_modref( wm ); + if (!mod->LoadCount) + free_modref( wm ); + else + unlock_modref( wm ); } + unlock_ldr_data( TRUE ); }
/*********************************************************************** @@ -3365,7 +3565,11 @@ static void MODULE_DecRefCount( WINE_MODREF *wm )
for ( i = 0; i < wm->nDeps; i++ ) if ( wm->deps[i] ) + { + lock_modref( wm->deps[i] ); MODULE_DecRefCount( wm->deps[i] ); + unlock_modref( wm->deps[i] ); + }
wm->ldr.Flags &= ~LDR_UNLOAD_IN_PROGRESS;
@@ -3396,8 +3600,8 @@ NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
/* Recursively decrement reference counts */ MODULE_DecRefCount( wm ); - /* Call process detach notifications */ + unlock_modref( wm ); if ( free_lib_count <= 1 ) { process_detach(); @@ -3516,6 +3720,8 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR imports_fixup_done = TRUE; }
+ unlock_modref( wm ); + RtlAcquirePebLock(); InsertHeadList( &tls_links, &NtCurrentTeb()->TlsLinks ); RtlReleasePebLock(); @@ -3539,7 +3745,10 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR for (i = 0; i < wm->nDeps; i++) { if (!wm->deps[i]) continue; - if ((status = process_attach( wm->deps[i], context )) != STATUS_SUCCESS) + lock_modref( wm->deps[i] ); + status = process_attach( wm->deps[i], context ); + unlock_modref( wm->deps[i] ); + if (status) { if (last_failed_modref) ERR( "%s failed to initialize, aborting\n", @@ -4051,12 +4260,15 @@ static NTSTATUS process_init(void) &meminfo, sizeof(meminfo), NULL ); status = build_builtin_module( params->DllPath.Buffer, &nt_name, meminfo.AllocationBase, 0, &wm ); assert( !status ); + unlock_modref( wm );
if ((status = load_dll( params->DllPath.Buffer, kernel32W, NULL, 0, &wm )) != STATUS_SUCCESS) { MESSAGE( "wine: could not load kernel32.dll, status %x\n", status ); NtTerminateProcess( GetCurrentProcess(), status ); } + unlock_modref( wm ); + RtlInitAnsiString( &func_name, "BaseThreadInitThunk" ); if ((status = LdrGetProcedureAddress( wm->ldr.DllBase, &func_name, 0, (void **)&pBaseThreadInitThunk )) != STATUS_SUCCESS) @@ -4070,6 +4282,8 @@ static NTSTATUS process_init(void) if (!(status = load_dll( params->DllPath.Buffer, params->ImagePathName.Buffer, NULL, DONT_RESOLVE_DLL_REFERENCES, &wm ))) { + unlock_modref( wm ); + peb->ImageBaseAddress = wm->ldr.DllBase; TRACE( "main exe loaded %s at %p\n", debugstr_us(¶ms->ImagePathName), peb->ImageBaseAddress ); if (wm->ldr.Flags & LDR_IMAGE_IS_DLL) @@ -4128,7 +4342,8 @@ static NTSTATUS process_init(void) } #endif
- /* the main exe needs to be the first in the load order list */ + /* the main exe needs to be the first in the load order list. + * ldr_data_section locking is redundant here. */ RemoveEntryList( &wm->ldr.InLoadOrderLinks ); InsertHeadList( &peb->LdrData->InLoadOrderModuleList, &wm->ldr.InLoadOrderLinks ); RemoveEntryList( &wm->ldr.InMemoryOrderLinks );