Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntdll/loader.c | 353 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 286 insertions(+), 67 deletions(-)
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 368448c9f8d..e6895d66bd4 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; + + lock_ldr_data( FALSE );
- if (cached_modref && !memcmp( &cached_modref->id, id, sizeof(*id) )) return cached_modref; + 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,14 +706,16 @@ 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 mod_name[32]; const char *end = strrchr(forward, '.'); FARPROC proc = NULL; + char *name;
if (!end) return NULL; if ((end - forward) * sizeof(WCHAR) >= sizeof(mod_name)) return NULL; @@ -622,9 +727,19 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS memcpy( mod_name + (end - forward), dllW, sizeof(dllW) ); }
+ if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, strlen( end + 1 ) + 1 ))) + { + ERR("no memory.\n"); + return NULL; + } + 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)) { @@ -635,35 +750,36 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS } else if (process_attach( wm, NULL ) != STATUS_SUCCESS) { + unlock_modref( wm ); LdrUnloadDll( wm->ldr.DllBase ); wm = NULL; } } - if (!wm) { - 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) ); + ERR( "function not found for forward '%s'.", forward ); } +done: + RtlFreeHeap( GetProcessHeap(), 0, name ); + *wm_imp = get_modref( module ); return proc; }
@@ -673,11 +789,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 );
@@ -693,16 +809,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; @@ -713,11 +831,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; @@ -727,7 +845,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 */ @@ -736,7 +854,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; } @@ -751,8 +869,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; @@ -780,6 +899,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)) @@ -791,7 +912,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 ); @@ -806,6 +931,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; }
@@ -852,8 +978,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) ); @@ -867,9 +994,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 ); @@ -888,6 +1016,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; }
@@ -1079,12 +1208,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; }
@@ -1094,8 +1227,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; @@ -1145,12 +1282,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 ); @@ -1178,6 +1316,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) ))) { @@ -1199,11 +1339,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)) { @@ -1402,19 +1545,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; @@ -1423,6 +1575,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 @@ -1436,6 +1589,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 */ @@ -1462,12 +1617,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 */ @@ -1485,6 +1644,7 @@ static void process_detach(void) { PLIST_ENTRY mark, entry; PLDR_DATA_TABLE_ENTRY mod; + WINE_MODREF *wm;
mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList; do @@ -1499,10 +1659,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 @@ -1554,6 +1716,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 );
@@ -1718,17 +1881,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; @@ -1736,6 +1900,9 @@ NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name, } }
+ if (modref) + unlock_modref( modref ); + RtlLeaveCriticalSection( &loader_section ); return ret; } @@ -1908,8 +2075,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 @@ -2653,6 +2823,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) { @@ -2711,6 +2883,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 */ @@ -2770,6 +2943,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; @@ -2798,11 +2972,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; @@ -2827,7 +3010,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 ); @@ -2860,6 +3047,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;
@@ -3236,6 +3424,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) @@ -3280,6 +3469,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)) @@ -3294,11 +3484,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 ); @@ -3318,13 +3512,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 */ @@ -3333,9 +3532,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 ); }
/*********************************************************************** @@ -3362,7 +3566,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;
@@ -3393,8 +3601,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(); @@ -3513,6 +3721,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(); @@ -3536,7 +3746,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", @@ -4048,12 +4261,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) @@ -4067,6 +4283,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) @@ -4125,7 +4343,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 );
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/kernel32/tests/loader.c | 70 ++++++++++++++++++++++++++++++++++++ dlls/ntdll/loader.c | 6 ++-- 2 files changed, 72 insertions(+), 4 deletions(-)
diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index 67fd62ef6aa..5d8991bf0f0 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -70,6 +70,7 @@ static NTSTATUS (WINAPI *pLdrLockLoaderLock)(ULONG, ULONG *, ULONG_PTR *); static NTSTATUS (WINAPI *pLdrUnlockLoaderLock)(ULONG, ULONG_PTR); static NTSTATUS (WINAPI *pLdrLoadDll)(LPCWSTR,DWORD,const UNICODE_STRING *,HMODULE*); static NTSTATUS (WINAPI *pLdrUnloadDll)(HMODULE); +static NTSTATUS (WINAPI *pLdrGetProcedureAddress)(HMODULE, const ANSI_STRING *, ULONG, void **); static void (WINAPI *pRtlInitUnicodeString)(PUNICODE_STRING,LPCWSTR); static void (WINAPI *pRtlAcquirePebLock)(void); static void (WINAPI *pRtlReleasePebLock)(void); @@ -3992,6 +3993,73 @@ static void test_LoadPackagedLibrary(void) h, GetLastError()); }
+static HANDLE test_loader_lock_event, test_loader_lock_test_done_event; + +static DWORD WINAPI test_loader_lock_thread(void *param) +{ + NTSTATUS status; + ULONG_PTR magic; + DWORD ret; + + status = pLdrLockLoaderLock(0, NULL, &magic); + ok(!status, "Got unexpected status %#x.\n", status); + pRtlAcquirePebLock(); + SetEvent(test_loader_lock_event); + + ret = WaitForSingleObject(test_loader_lock_test_done_event, 2000); + ok(ret == WAIT_OBJECT_0 || broken(ret == WAIT_TIMEOUT) /* before Win8 */, + "Got unexpected ret %#x.\n", ret); + pRtlReleasePebLock(); + status = pLdrUnlockLoaderLock(0, magic); + ok(!status, "Got unexpected status %#x.\n", status); + + return 0; +} + +static void test_loader_lock_scope(void) +{ + ANSI_STRING name; + HMODULE hmodule; + ULONG_PTR magic; + NTSTATUS status; + HANDLE hthread; + void *address; + ULONG result; + DWORD ret; + + if (!pRtlAcquirePebLock || !pLdrLockLoaderLock) + { + win_skip("RtlAcquirePebLock or LdrLockLoaderLock is not available.\n"); + return; + } + + test_loader_lock_event = CreateEventA(NULL, FALSE, FALSE, NULL); + test_loader_lock_test_done_event = CreateEventA(NULL, FALSE, FALSE, NULL); + + hmodule = GetModuleHandleA("ntdll.dll"); + ok(!!hmodule, "Got NULL hmodule.\n"); + + hthread = CreateThread(NULL, 0, test_loader_lock_thread, NULL, 0, NULL); + ok(!!hthread, "Thread creation failed.\n"); + + ret = WaitForSingleObject(test_loader_lock_event, INFINITE); + ok(ret == WAIT_OBJECT_0, "Got unexpected ret %#x.\n", ret); + + result = 0xdeadbeef; + status = pLdrLockLoaderLock(2, &result, &magic); + ok(!status && result == 2, "Got unexpected status %#x, result %#x,\n", status, result); + + RtlInitAnsiString(&name, "LdrLockLoaderLock"); + address = (void *)0xdeadbeef; + /* Locks up on loader lock before Win7. */ + status = pLdrGetProcedureAddress(hmodule, &name, 0, &address); + ok(!status && address == pLdrLockLoaderLock, "Got unexpected status %#x, address %p.\n", status, address); + + SetEvent(test_loader_lock_test_done_event); + ret = WaitForSingleObject(hthread, INFINITE); + ok(ret == WAIT_OBJECT_0, "Got unexpected ret %#x.\n", ret); +} + START_TEST(loader) { int argc; @@ -4016,6 +4084,7 @@ START_TEST(loader) pLdrUnlockLoaderLock = (void *)GetProcAddress(ntdll, "LdrUnlockLoaderLock"); pLdrLoadDll = (void *)GetProcAddress(ntdll, "LdrLoadDll"); pLdrUnloadDll = (void *)GetProcAddress(ntdll, "LdrUnloadDll"); + pLdrGetProcedureAddress = (void *)GetProcAddress(ntdll, "LdrGetProcedureAddress"); pRtlInitUnicodeString = (void *)GetProcAddress(ntdll, "RtlInitUnicodeString"); pRtlAcquirePebLock = (void *)GetProcAddress(ntdll, "RtlAcquirePebLock"); pRtlReleasePebLock = (void *)GetProcAddress(ntdll, "RtlReleasePebLock"); @@ -4068,6 +4137,7 @@ START_TEST(loader) test_dll_file( "kernel32.dll" ); test_dll_file( "advapi32.dll" ); test_dll_file( "user32.dll" ); + test_loader_lock_scope(); /* loader test must be last, it can corrupt the internal loader state on Windows */ test_Loader(); } diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index e6895d66bd4..5a429b3f7a8 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -704,7 +704,6 @@ static WINE_MODREF **grow_module_deps( WINE_MODREF *wm, int count ) * find_forwarded_export * * Find the final function pointer for a forwarded function. - * The loader_section must be locked while calling this function. */ static FARPROC find_forwarded_export( WINE_MODREF **wm_imp, const char *forward, LPCWSTR load_path ) { @@ -740,6 +739,7 @@ static FARPROC find_forwarded_export( WINE_MODREF **wm_imp, const char *forward, if (!(wm = find_basename_module( mod_name ))) { TRACE( "delay loading %s.\n", debugstr_w(mod_name) ); + RtlEnterCriticalSection( &loader_section ); if (load_dll( load_path, mod_name, dllW, 0, &wm ) == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) { @@ -755,6 +755,7 @@ static FARPROC find_forwarded_export( WINE_MODREF **wm_imp, const char *forward, wm = NULL; } } + RtlLeaveCriticalSection( &loader_section ); if (!wm) { ERR( "module not found, mod_name %s, path %s.\n", debugstr_w(mod_name), debugstr_w(load_path) ); @@ -1883,8 +1884,6 @@ NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name, 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 (!(modref = get_modref( module ))) ret = STATUS_DLL_NOT_FOUND; else if ((exports = RtlImageDirectoryEntryToData( module, TRUE, @@ -1903,7 +1902,6 @@ NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name, if (modref) unlock_modref( modref );
- RtlLeaveCriticalSection( &loader_section ); return ret; }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=81522
Your paranoid android.
=== w10pro64_ar (32 bit report) ===
kernel32: loader.c:2799: Test failed: attached thread count should be 2
=== w10pro64_he (32 bit report) ===
kernel32: loader.c:2799: Test failed: attached thread count should be 2
=== w10pro64_zh_CN (32 bit report) ===
kernel32: loader.c:2799: Test failed: attached thread count should be 2
=== debiant (32 bit report) ===
kernel32: loader.c:3965: Test failed: ntdll.dll:0: wrong OptionalHeader.AddressOfEntryPoint 60650 / 5f730 loader.c:3969: Test failed: ntdll.dll:0: wrong OptionalHeader.DataDirectory[i].VirtualAddress 76000 / 74000 loader.c:3969: Test failed: ntdll.dll:1: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8a000 / 88000 loader.c:3969: Test failed: ntdll.dll:2: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8b000 / 89000 loader.c:3969: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8c000 / 8a000 loader.c:3970: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].Size 3c04 / 3b10 loader.c:3975: Test failed: ntdll.dll: wrong section 0 loader.c:3975: Test failed: ntdll.dll: wrong section 1 loader.c:3975: Test failed: ntdll.dll: wrong section 2 loader.c:3975: Test failed: ntdll.dll: wrong section 3 loader.c:3975: Test failed: ntdll.dll: wrong section 4 loader.c:3975: Test failed: ntdll.dll: wrong section 5 loader.c:3975: Test failed: ntdll.dll: wrong section 6 loader.c:3975: Test failed: ntdll.dll: wrong section 7 loader.c:3975: Test failed: ntdll.dll: wrong section 8 loader.c:3975: Test failed: ntdll.dll: wrong section 9 loader.c:3975: Test failed: ntdll.dll: wrong section 10 loader.c:3975: Test failed: ntdll.dll: wrong section 11 loader.c:3975: Test failed: ntdll.dll: wrong section 12 loader.c:3975: Test failed: ntdll.dll: wrong section 13 loader.c:3975: Test failed: ntdll.dll: wrong section 14 loader.c:3975: Test failed: ntdll.dll: wrong section 15
=== debiant (32 bit French report) ===
kernel32: loader.c:3965: Test failed: ntdll.dll:0: wrong OptionalHeader.AddressOfEntryPoint 60650 / 5f730 loader.c:3969: Test failed: ntdll.dll:0: wrong OptionalHeader.DataDirectory[i].VirtualAddress 76000 / 74000 loader.c:3969: Test failed: ntdll.dll:1: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8a000 / 88000 loader.c:3969: Test failed: ntdll.dll:2: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8b000 / 89000 loader.c:3969: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8c000 / 8a000 loader.c:3970: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].Size 3c04 / 3b10 loader.c:3975: Test failed: ntdll.dll: wrong section 0 loader.c:3975: Test failed: ntdll.dll: wrong section 1 loader.c:3975: Test failed: ntdll.dll: wrong section 2 loader.c:3975: Test failed: ntdll.dll: wrong section 3 loader.c:3975: Test failed: ntdll.dll: wrong section 4 loader.c:3975: Test failed: ntdll.dll: wrong section 5 loader.c:3975: Test failed: ntdll.dll: wrong section 6 loader.c:3975: Test failed: ntdll.dll: wrong section 7 loader.c:3975: Test failed: ntdll.dll: wrong section 8 loader.c:3975: Test failed: ntdll.dll: wrong section 9 loader.c:3975: Test failed: ntdll.dll: wrong section 10 loader.c:3975: Test failed: ntdll.dll: wrong section 11 loader.c:3975: Test failed: ntdll.dll: wrong section 12 loader.c:3975: Test failed: ntdll.dll: wrong section 13 loader.c:3975: Test failed: ntdll.dll: wrong section 14 loader.c:3975: Test failed: ntdll.dll: wrong section 15
=== debiant (32 bit Japanese:Japan report) ===
kernel32: loader.c:3965: Test failed: ntdll.dll:0: wrong OptionalHeader.AddressOfEntryPoint 60650 / 5f730 loader.c:3969: Test failed: ntdll.dll:0: wrong OptionalHeader.DataDirectory[i].VirtualAddress 76000 / 74000 loader.c:3969: Test failed: ntdll.dll:1: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8a000 / 88000 loader.c:3969: Test failed: ntdll.dll:2: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8b000 / 89000 loader.c:3969: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8c000 / 8a000 loader.c:3970: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].Size 3c04 / 3b10 loader.c:3975: Test failed: ntdll.dll: wrong section 0 loader.c:3975: Test failed: ntdll.dll: wrong section 1 loader.c:3975: Test failed: ntdll.dll: wrong section 2 loader.c:3975: Test failed: ntdll.dll: wrong section 3 loader.c:3975: Test failed: ntdll.dll: wrong section 4 loader.c:3975: Test failed: ntdll.dll: wrong section 5 loader.c:3975: Test failed: ntdll.dll: wrong section 6 loader.c:3975: Test failed: ntdll.dll: wrong section 7 loader.c:3975: Test failed: ntdll.dll: wrong section 8 loader.c:3975: Test failed: ntdll.dll: wrong section 9 loader.c:3975: Test failed: ntdll.dll: wrong section 10 loader.c:3975: Test failed: ntdll.dll: wrong section 11 loader.c:3975: Test failed: ntdll.dll: wrong section 12 loader.c:3975: Test failed: ntdll.dll: wrong section 13 loader.c:3975: Test failed: ntdll.dll: wrong section 14 loader.c:3975: Test failed: ntdll.dll: wrong section 15
=== debiant (32 bit Chinese:China report) ===
kernel32: loader.c:3965: Test failed: ntdll.dll:0: wrong OptionalHeader.AddressOfEntryPoint 60650 / 5f730 loader.c:3969: Test failed: ntdll.dll:0: wrong OptionalHeader.DataDirectory[i].VirtualAddress 76000 / 74000 loader.c:3969: Test failed: ntdll.dll:1: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8a000 / 88000 loader.c:3969: Test failed: ntdll.dll:2: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8b000 / 89000 loader.c:3969: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8c000 / 8a000 loader.c:3970: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].Size 3c04 / 3b10 loader.c:3975: Test failed: ntdll.dll: wrong section 0 loader.c:3975: Test failed: ntdll.dll: wrong section 1 loader.c:3975: Test failed: ntdll.dll: wrong section 2 loader.c:3975: Test failed: ntdll.dll: wrong section 3 loader.c:3975: Test failed: ntdll.dll: wrong section 4 loader.c:3975: Test failed: ntdll.dll: wrong section 5 loader.c:3975: Test failed: ntdll.dll: wrong section 6 loader.c:3975: Test failed: ntdll.dll: wrong section 7 loader.c:3975: Test failed: ntdll.dll: wrong section 8 loader.c:3975: Test failed: ntdll.dll: wrong section 9 loader.c:3975: Test failed: ntdll.dll: wrong section 10 loader.c:3975: Test failed: ntdll.dll: wrong section 11 loader.c:3975: Test failed: ntdll.dll: wrong section 12 loader.c:3975: Test failed: ntdll.dll: wrong section 13 loader.c:3975: Test failed: ntdll.dll: wrong section 14 loader.c:3975: Test failed: ntdll.dll: wrong section 15
=== debiant (32 bit WoW report) ===
kernel32: loader.c:3965: Test failed: ntdll.dll:0: wrong OptionalHeader.AddressOfEntryPoint 60650 / 5f730 loader.c:3969: Test failed: ntdll.dll:0: wrong OptionalHeader.DataDirectory[i].VirtualAddress 76000 / 74000 loader.c:3969: Test failed: ntdll.dll:1: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8a000 / 88000 loader.c:3969: Test failed: ntdll.dll:2: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8b000 / 89000 loader.c:3969: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8c000 / 8a000 loader.c:3970: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].Size 3c04 / 3b10 loader.c:3975: Test failed: ntdll.dll: wrong section 0 loader.c:3975: Test failed: ntdll.dll: wrong section 1 loader.c:3975: Test failed: ntdll.dll: wrong section 2 loader.c:3975: Test failed: ntdll.dll: wrong section 3 loader.c:3975: Test failed: ntdll.dll: wrong section 4 loader.c:3975: Test failed: ntdll.dll: wrong section 5 loader.c:3975: Test failed: ntdll.dll: wrong section 6 loader.c:3975: Test failed: ntdll.dll: wrong section 7 loader.c:3975: Test failed: ntdll.dll: wrong section 8 loader.c:3975: Test failed: ntdll.dll: wrong section 9 loader.c:3975: Test failed: ntdll.dll: wrong section 10 loader.c:3975: Test failed: ntdll.dll: wrong section 11 loader.c:3975: Test failed: ntdll.dll: wrong section 12 loader.c:3975: Test failed: ntdll.dll: wrong section 13 loader.c:3975: Test failed: ntdll.dll: wrong section 14 loader.c:3975: Test failed: ntdll.dll: wrong section 15
=== debiant (64 bit WoW report) ===
kernel32: loader.c:3965: Test failed: ntdll.dll:0: wrong OptionalHeader.AddressOfEntryPoint 60650 / 5f730 loader.c:3969: Test failed: ntdll.dll:0: wrong OptionalHeader.DataDirectory[i].VirtualAddress 76000 / 74000 loader.c:3969: Test failed: ntdll.dll:1: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8a000 / 88000 loader.c:3969: Test failed: ntdll.dll:2: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8b000 / 89000 loader.c:3969: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8c000 / 8a000 loader.c:3970: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].Size 3c04 / 3b10 loader.c:3975: Test failed: ntdll.dll: wrong section 0 loader.c:3975: Test failed: ntdll.dll: wrong section 1 loader.c:3975: Test failed: ntdll.dll: wrong section 2 loader.c:3975: Test failed: ntdll.dll: wrong section 3 loader.c:3975: Test failed: ntdll.dll: wrong section 4 loader.c:3975: Test failed: ntdll.dll: wrong section 5 loader.c:3975: Test failed: ntdll.dll: wrong section 6 loader.c:3975: Test failed: ntdll.dll: wrong section 7 loader.c:3975: Test failed: ntdll.dll: wrong section 8 loader.c:3975: Test failed: ntdll.dll: wrong section 9 loader.c:3975: Test failed: ntdll.dll: wrong section 10 loader.c:3975: Test failed: ntdll.dll: wrong section 11 loader.c:3975: Test failed: ntdll.dll: wrong section 12 loader.c:3975: Test failed: ntdll.dll: wrong section 13 loader.c:3975: Test failed: ntdll.dll: wrong section 14 loader.c:3975: Test failed: ntdll.dll: wrong section 15
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntdll/loader.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-)
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 5a429b3f7a8..065bd62cac0 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -2388,7 +2388,8 @@ static NTSTATUS get_dll_load_path_search_flags( LPCWSTR module, DWORD flags, WCH * Open a file for a new dll. Helper for find_dll_file. */ static NTSTATUS open_dll_file( UNICODE_STRING *nt_name, WINE_MODREF **pwm, void **module, - SECTION_IMAGE_INFORMATION *image_info, struct file_id *id ) + SECTION_IMAGE_INFORMATION *image_info, struct file_id *id, + BOOL loaded_only ) { FILE_BASIC_INFORMATION info; OBJECT_ATTRIBUTES attr; @@ -2441,6 +2442,14 @@ static NTSTATUS open_dll_file( UNICODE_STRING *nt_name, WINE_MODREF **pwm, void } }
+ if (loaded_only) + { + NtClose( handle ); + NtUnmapViewOfSection( NtCurrentProcess(), *module ); + *module = NULL; + return STATUS_DLL_NOT_FOUND; + } + size.QuadPart = 0; status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_EXECUTE, @@ -2665,7 +2674,7 @@ done: */ static NTSTATUS search_dll_file( LPCWSTR paths, LPCWSTR search, UNICODE_STRING *nt_name, WINE_MODREF **pwm, void **module, SECTION_IMAGE_INFORMATION *image_info, - struct file_id *id ) + struct file_id *id, BOOL loaded_only ) { WCHAR *name; BOOL found_image = FALSE; @@ -2692,7 +2701,7 @@ static NTSTATUS search_dll_file( LPCWSTR paths, LPCWSTR search, UNICODE_STRING * nt_name->Buffer = NULL; if ((status = RtlDosPathNameToNtPathName_U_WithStatus( name, nt_name, NULL, NULL ))) goto done;
- status = open_dll_file( nt_name, pwm, module, image_info, id ); + status = open_dll_file( nt_name, pwm, module, image_info, id, loaded_only ); if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) found_image = TRUE; else if (status != STATUS_DLL_NOT_FOUND) goto done; RtlFreeUnicodeString( nt_name ); @@ -2721,7 +2730,8 @@ done: */ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext, UNICODE_STRING *nt_name, WINE_MODREF **pwm, void **module, - SECTION_IMAGE_INFORMATION *image_info, struct file_id *id ) + SECTION_IMAGE_INFORMATION *image_info, struct file_id *id, + BOOL loaded_only ) { WCHAR *ext, *dllname; NTSTATUS status; @@ -2772,9 +2782,9 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, con }
if (RtlDetermineDosPathNameType_U( libname ) == RELATIVE_PATH) - status = search_dll_file( load_path, libname, nt_name, pwm, module, image_info, id ); + status = search_dll_file( load_path, libname, nt_name, pwm, module, image_info, id, loaded_only ); else if (!(status = RtlDosPathNameToNtPathName_U_WithStatus( libname, nt_name, NULL, NULL ))) - status = open_dll_file( nt_name, pwm, module, image_info, id ); + status = open_dll_file( nt_name, pwm, module, image_info, id, loaded_only );
if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) status = STATUS_INVALID_IMAGE_FORMAT;
@@ -2804,7 +2814,7 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WC
TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) );
- nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &module, &image_info, &id ); + nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &module, &image_info, &id, FALSE );
if (*pwm) /* found already loaded module */ { @@ -2885,7 +2895,7 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WC LdrUnloadDll( (*pwm)->ldr.DllBase ); nts = STATUS_DLL_NOT_FOUND; /* map the dll again if it was unmapped */ - if (!module && open_dll_file( &nt_name, pwm, &module, &image_info, &id )) break; + if (!module && open_dll_file( &nt_name, pwm, &module, &image_info, &id, FALSE )) break; } if (nts == STATUS_DLL_NOT_FOUND) nts = load_native_dll( load_path, &nt_name, &module, &image_info, &id, flags, pwm ); @@ -3006,18 +3016,12 @@ NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_S
if (!load_path) load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
- status = find_dll_file( load_path, name->Buffer, dllW, &nt_name, &wm, &module, &image_info, &id ); - - if (wm) + if (!(status = find_dll_file( load_path, name->Buffer, dllW, + &nt_name, &wm, &module, &image_info, &id, TRUE ))) { *base = wm->ldr.DllBase; unlock_modref( wm ); } - else - { - if (status == STATUS_SUCCESS) NtUnmapViewOfSection( NtCurrentProcess(), module ); - status = STATUS_DLL_NOT_FOUND; - } RtlFreeUnicodeString( &nt_name );
RtlLeaveCriticalSection( &loader_section );
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/kernel32/tests/loader.c | 5 ++--- dlls/ntdll/loader.c | 3 --- 2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index 5d8991bf0f0..8b4be58036d 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -4036,9 +4036,6 @@ static void test_loader_lock_scope(void) test_loader_lock_event = CreateEventA(NULL, FALSE, FALSE, NULL); test_loader_lock_test_done_event = CreateEventA(NULL, FALSE, FALSE, NULL);
- hmodule = GetModuleHandleA("ntdll.dll"); - ok(!!hmodule, "Got NULL hmodule.\n"); - hthread = CreateThread(NULL, 0, test_loader_lock_thread, NULL, 0, NULL); ok(!!hthread, "Thread creation failed.\n");
@@ -4052,6 +4049,8 @@ static void test_loader_lock_scope(void) RtlInitAnsiString(&name, "LdrLockLoaderLock"); address = (void *)0xdeadbeef; /* Locks up on loader lock before Win7. */ + hmodule = GetModuleHandleA("ntdll.dll"); + ok(!!hmodule, "Got NULL hmodule.\n"); status = pLdrGetProcedureAddress(hmodule, &name, 0, &address); ok(!status && address == pLdrLockLoaderLock, "Got unexpected status %#x, address %p.\n", status, address);
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 065bd62cac0..6dd73a8c001 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -3012,8 +3012,6 @@ NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_S SECTION_IMAGE_INFORMATION image_info; struct file_id id;
- RtlEnterCriticalSection( &loader_section ); - if (!load_path) load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
if (!(status = find_dll_file( load_path, name->Buffer, dllW, @@ -3024,7 +3022,6 @@ NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_S } RtlFreeUnicodeString( &nt_name );
- RtlLeaveCriticalSection( &loader_section ); TRACE( "%s -> %p (load path %s)\n", debugstr_us(name), status ? NULL : *base, debugstr_w(load_path) ); return status; }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=81524
Your paranoid android.
=== w10pro64_2scr (32 bit report) ===
kernel32: loader.c:709: Test failed: 1180: wrong status c000011b/c0000131 loader.c:709: Test failed: 1180: wrong status c000011b/c0000130 loader.c:709: Test failed: 1197: wrong status c000011b/c0000130 loader.c:709: Test failed: 1202: wrong status c000011b/c0000130 loader.c:709: Test failed: 1207: wrong status c000011b/c000007b loader.c:709: Test failed: 1212: wrong status c000011b/c000007b loader.c:709: Test failed: 1217: wrong status c000011b/c000007b loader.c:709: Test failed: 1222: wrong status c000011b/c000007b loader.c:709: Test failed: 1227: wrong status c000011b/c000007b loader.c:709: Test failed: 1243: wrong status c000011b/0 loader.c:709: Test failed: 1247: wrong status c000011b/0 loader.c:709: Test failed: 1252: wrong status c000011b/0
=== w10pro64_ja (32 bit report) ===
kernel32: loader.c:2799: Test failed: attached thread count should be 2
=== w10pro64_zh_CN (32 bit report) ===
kernel32: loader.c:2799: Test failed: attached thread count should be 2
=== debiant (32 bit report) ===
kernel32: loader.c:3965: Test failed: ntdll.dll:0: wrong OptionalHeader.AddressOfEntryPoint 60610 / 5f730 loader.c:3969: Test failed: ntdll.dll:0: wrong OptionalHeader.DataDirectory[i].VirtualAddress 76000 / 74000 loader.c:3969: Test failed: ntdll.dll:1: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8a000 / 88000 loader.c:3969: Test failed: ntdll.dll:2: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8b000 / 89000 loader.c:3969: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8c000 / 8a000 loader.c:3970: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].Size 3bf8 / 3b10 loader.c:3975: Test failed: ntdll.dll: wrong section 0 loader.c:3975: Test failed: ntdll.dll: wrong section 1 loader.c:3975: Test failed: ntdll.dll: wrong section 2 loader.c:3975: Test failed: ntdll.dll: wrong section 3 loader.c:3975: Test failed: ntdll.dll: wrong section 4 loader.c:3975: Test failed: ntdll.dll: wrong section 5 loader.c:3975: Test failed: ntdll.dll: wrong section 6 loader.c:3975: Test failed: ntdll.dll: wrong section 7 loader.c:3975: Test failed: ntdll.dll: wrong section 8 loader.c:3975: Test failed: ntdll.dll: wrong section 9 loader.c:3975: Test failed: ntdll.dll: wrong section 10 loader.c:3975: Test failed: ntdll.dll: wrong section 11 loader.c:3975: Test failed: ntdll.dll: wrong section 12 loader.c:3975: Test failed: ntdll.dll: wrong section 13 loader.c:3975: Test failed: ntdll.dll: wrong section 14 loader.c:3975: Test failed: ntdll.dll: wrong section 15
=== debiant (32 bit French report) ===
kernel32: loader.c:3965: Test failed: ntdll.dll:0: wrong OptionalHeader.AddressOfEntryPoint 60610 / 5f730 loader.c:3969: Test failed: ntdll.dll:0: wrong OptionalHeader.DataDirectory[i].VirtualAddress 76000 / 74000 loader.c:3969: Test failed: ntdll.dll:1: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8a000 / 88000 loader.c:3969: Test failed: ntdll.dll:2: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8b000 / 89000 loader.c:3969: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8c000 / 8a000 loader.c:3970: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].Size 3bf8 / 3b10 loader.c:3975: Test failed: ntdll.dll: wrong section 0 loader.c:3975: Test failed: ntdll.dll: wrong section 1 loader.c:3975: Test failed: ntdll.dll: wrong section 2 loader.c:3975: Test failed: ntdll.dll: wrong section 3 loader.c:3975: Test failed: ntdll.dll: wrong section 4 loader.c:3975: Test failed: ntdll.dll: wrong section 5 loader.c:3975: Test failed: ntdll.dll: wrong section 6 loader.c:3975: Test failed: ntdll.dll: wrong section 7 loader.c:3975: Test failed: ntdll.dll: wrong section 8 loader.c:3975: Test failed: ntdll.dll: wrong section 9 loader.c:3975: Test failed: ntdll.dll: wrong section 10 loader.c:3975: Test failed: ntdll.dll: wrong section 11 loader.c:3975: Test failed: ntdll.dll: wrong section 12 loader.c:3975: Test failed: ntdll.dll: wrong section 13 loader.c:3975: Test failed: ntdll.dll: wrong section 14 loader.c:3975: Test failed: ntdll.dll: wrong section 15
=== debiant (32 bit Japanese:Japan report) ===
kernel32: loader.c:3965: Test failed: ntdll.dll:0: wrong OptionalHeader.AddressOfEntryPoint 60610 / 5f730 loader.c:3969: Test failed: ntdll.dll:0: wrong OptionalHeader.DataDirectory[i].VirtualAddress 76000 / 74000 loader.c:3969: Test failed: ntdll.dll:1: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8a000 / 88000 loader.c:3969: Test failed: ntdll.dll:2: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8b000 / 89000 loader.c:3969: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8c000 / 8a000 loader.c:3970: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].Size 3bf8 / 3b10 loader.c:3975: Test failed: ntdll.dll: wrong section 0 loader.c:3975: Test failed: ntdll.dll: wrong section 1 loader.c:3975: Test failed: ntdll.dll: wrong section 2 loader.c:3975: Test failed: ntdll.dll: wrong section 3 loader.c:3975: Test failed: ntdll.dll: wrong section 4 loader.c:3975: Test failed: ntdll.dll: wrong section 5 loader.c:3975: Test failed: ntdll.dll: wrong section 6 loader.c:3975: Test failed: ntdll.dll: wrong section 7 loader.c:3975: Test failed: ntdll.dll: wrong section 8 loader.c:3975: Test failed: ntdll.dll: wrong section 9 loader.c:3975: Test failed: ntdll.dll: wrong section 10 loader.c:3975: Test failed: ntdll.dll: wrong section 11 loader.c:3975: Test failed: ntdll.dll: wrong section 12 loader.c:3975: Test failed: ntdll.dll: wrong section 13 loader.c:3975: Test failed: ntdll.dll: wrong section 14 loader.c:3975: Test failed: ntdll.dll: wrong section 15
=== debiant (32 bit Chinese:China report) ===
kernel32: loader.c:3965: Test failed: ntdll.dll:0: wrong OptionalHeader.AddressOfEntryPoint 60610 / 5f730 loader.c:3969: Test failed: ntdll.dll:0: wrong OptionalHeader.DataDirectory[i].VirtualAddress 76000 / 74000 loader.c:3969: Test failed: ntdll.dll:1: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8a000 / 88000 loader.c:3969: Test failed: ntdll.dll:2: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8b000 / 89000 loader.c:3969: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8c000 / 8a000 loader.c:3970: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].Size 3bf8 / 3b10 loader.c:3975: Test failed: ntdll.dll: wrong section 0 loader.c:3975: Test failed: ntdll.dll: wrong section 1 loader.c:3975: Test failed: ntdll.dll: wrong section 2 loader.c:3975: Test failed: ntdll.dll: wrong section 3 loader.c:3975: Test failed: ntdll.dll: wrong section 4 loader.c:3975: Test failed: ntdll.dll: wrong section 5 loader.c:3975: Test failed: ntdll.dll: wrong section 6 loader.c:3975: Test failed: ntdll.dll: wrong section 7 loader.c:3975: Test failed: ntdll.dll: wrong section 8 loader.c:3975: Test failed: ntdll.dll: wrong section 9 loader.c:3975: Test failed: ntdll.dll: wrong section 10 loader.c:3975: Test failed: ntdll.dll: wrong section 11 loader.c:3975: Test failed: ntdll.dll: wrong section 12 loader.c:3975: Test failed: ntdll.dll: wrong section 13 loader.c:3975: Test failed: ntdll.dll: wrong section 14 loader.c:3975: Test failed: ntdll.dll: wrong section 15
=== debiant (32 bit WoW report) ===
kernel32: loader.c:3965: Test failed: ntdll.dll:0: wrong OptionalHeader.AddressOfEntryPoint 60610 / 5f730 loader.c:3969: Test failed: ntdll.dll:0: wrong OptionalHeader.DataDirectory[i].VirtualAddress 76000 / 74000 loader.c:3969: Test failed: ntdll.dll:1: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8a000 / 88000 loader.c:3969: Test failed: ntdll.dll:2: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8b000 / 89000 loader.c:3969: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8c000 / 8a000 loader.c:3970: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].Size 3bf8 / 3b10 loader.c:3975: Test failed: ntdll.dll: wrong section 0 loader.c:3975: Test failed: ntdll.dll: wrong section 1 loader.c:3975: Test failed: ntdll.dll: wrong section 2 loader.c:3975: Test failed: ntdll.dll: wrong section 3 loader.c:3975: Test failed: ntdll.dll: wrong section 4 loader.c:3975: Test failed: ntdll.dll: wrong section 5 loader.c:3975: Test failed: ntdll.dll: wrong section 6 loader.c:3975: Test failed: ntdll.dll: wrong section 7 loader.c:3975: Test failed: ntdll.dll: wrong section 8 loader.c:3975: Test failed: ntdll.dll: wrong section 9 loader.c:3975: Test failed: ntdll.dll: wrong section 10 loader.c:3975: Test failed: ntdll.dll: wrong section 11 loader.c:3975: Test failed: ntdll.dll: wrong section 12 loader.c:3975: Test failed: ntdll.dll: wrong section 13 loader.c:3975: Test failed: ntdll.dll: wrong section 14 loader.c:3975: Test failed: ntdll.dll: wrong section 15
=== debiant (64 bit WoW report) ===
kernel32: loader.c:3965: Test failed: ntdll.dll:0: wrong OptionalHeader.AddressOfEntryPoint 60610 / 5f730 loader.c:3969: Test failed: ntdll.dll:0: wrong OptionalHeader.DataDirectory[i].VirtualAddress 76000 / 74000 loader.c:3969: Test failed: ntdll.dll:1: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8a000 / 88000 loader.c:3969: Test failed: ntdll.dll:2: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8b000 / 89000 loader.c:3969: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].VirtualAddress 8c000 / 8a000 loader.c:3970: Test failed: ntdll.dll:5: wrong OptionalHeader.DataDirectory[i].Size 3bf8 / 3b10 loader.c:3975: Test failed: ntdll.dll: wrong section 0 loader.c:3975: Test failed: ntdll.dll: wrong section 1 loader.c:3975: Test failed: ntdll.dll: wrong section 2 loader.c:3975: Test failed: ntdll.dll: wrong section 3 loader.c:3975: Test failed: ntdll.dll: wrong section 4 loader.c:3975: Test failed: ntdll.dll: wrong section 5 loader.c:3975: Test failed: ntdll.dll: wrong section 6 loader.c:3975: Test failed: ntdll.dll: wrong section 7 loader.c:3975: Test failed: ntdll.dll: wrong section 8 loader.c:3975: Test failed: ntdll.dll: wrong section 9 loader.c:3975: Test failed: ntdll.dll: wrong section 10 loader.c:3975: Test failed: ntdll.dll: wrong section 11 loader.c:3975: Test failed: ntdll.dll: wrong section 12 loader.c:3975: Test failed: ntdll.dll: wrong section 13 loader.c:3975: Test failed: ntdll.dll: wrong section 14 loader.c:3975: Test failed: ntdll.dll: wrong section 15