[resend PATCH v2 1/4] ntdll: Introduce ldr_data_section and per-module locks.
Paul Gofman
pgofman at codeweavers.com
Fri Nov 27 05:11:55 CST 2020
Signed-off-by: Paul Gofman <pgofman at 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 );
--
2.28.0
More information about the wine-devel
mailing list