Commit 1cee60d0 authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Check file identity in addition to file name to find a loaded module.

parent 97b09074
......@@ -1282,14 +1282,11 @@ static void test_filenames(void)
mod2 = GetModuleHandleA( short_path );
ok( mod == mod2, "wrong module %p for %s\n", mod2, short_path );
mod2 = GetModuleHandleA( long_path );
todo_wine
ok( mod == mod2, "wrong module %p for %s\n", mod2, long_path );
mod2 = LoadLibraryA( long_path );
ok( mod2 != NULL, "loading failed err %u\n", GetLastError() );
todo_wine
ok( mod == mod2, "library loaded twice\n" );
GetModuleFileNameA( mod2, buffer, MAX_PATH );
todo_wine
ok( !lstrcmpiA( buffer, short_path ), "got wrong path %s / %s\n", buffer, short_path );
FreeLibrary( mod2 );
FreeLibrary( mod );
......@@ -1299,16 +1296,13 @@ static void test_filenames(void)
GetModuleFileNameA( mod, buffer, MAX_PATH );
ok( !lstrcmpiA( buffer, long_path ), "got wrong path %s / %s\n", buffer, long_path );
mod2 = GetModuleHandleA( short_path );
todo_wine
ok( mod == mod2, "wrong module %p for %s\n", mod2, short_path );
mod2 = GetModuleHandleA( long_path );
ok( mod == mod2, "wrong module %p for %s\n", mod2, long_path );
mod2 = LoadLibraryA( short_path );
ok( mod2 != NULL, "loading failed err %u\n", GetLastError() );
todo_wine
ok( mod == mod2, "library loaded twice\n" );
GetModuleFileNameA( mod2, buffer, MAX_PATH );
todo_wine
ok( !lstrcmpiA( buffer, long_path ), "got wrong path %s / %s\n", buffer, long_path );
FreeLibrary( mod2 );
FreeLibrary( mod );
......@@ -1324,14 +1318,11 @@ static void test_filenames(void)
GetModuleFileNameA( mod, buffer, MAX_PATH );
ok( !lstrcmpiA( buffer, dll_name ), "got wrong path %s / %s\n", buffer, dll_name );
mod2 = GetModuleHandleA( long_path );
todo_wine
ok( mod == mod2, "wrong module %p for %s\n", mod2, long_path );
mod2 = LoadLibraryA( long_path );
ok( mod2 != NULL, "loading failed err %u\n", GetLastError() );
todo_wine
ok( mod == mod2, "library loaded twice\n" );
GetModuleFileNameA( mod2, buffer, MAX_PATH );
todo_wine
ok( !lstrcmpiA( buffer, dll_name ), "got wrong path %s / %s\n", buffer, short_path );
FreeLibrary( mod2 );
FreeLibrary( mod );
......
......@@ -87,6 +87,8 @@ static const WCHAR dllW[] = {'.','d','l','l',0};
typedef struct _wine_modref
{
LDR_MODULE ldr;
dev_t dev;
ino_t ino;
int nDeps;
struct _wine_modref **deps;
} WINE_MODREF;
......@@ -418,6 +420,35 @@ static WINE_MODREF *find_fullname_module( LPCWSTR 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( HANDLE handle, struct stat *st )
{
LIST_ENTRY *mark, *entry;
if (cached_modref && cached_modref->dev == st->st_dev && cached_modref->ino == st->st_ino)
return cached_modref;
mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
for (entry = mark->Flink; entry != mark; entry = entry->Flink)
{
LDR_MODULE *mod = CONTAINING_RECORD( entry, LDR_MODULE, InLoadOrderModuleList );
WINE_MODREF *wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
if (wm->dev == st->st_dev && wm->ino == st->st_ino)
{
cached_modref = wm;
return wm;
}
}
return NULL;
}
/*************************************************************************
* find_forwarded_export
*
......@@ -998,21 +1029,13 @@ static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename )
const WCHAR *p;
const IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
if (!(wm = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*wm) ))) return NULL;
wm->nDeps = 0;
wm->deps = NULL;
if (!(wm = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wm) ))) return NULL;
wm->ldr.BaseAddress = hModule;
wm->ldr.EntryPoint = NULL;
wm->ldr.SizeOfImage = nt->OptionalHeader.SizeOfImage;
wm->ldr.Flags = LDR_DONT_RESOLVE_REFS;
wm->ldr.TlsIndex = -1;
wm->ldr.LoadCount = 1;
wm->ldr.SectionHandle = NULL;
wm->ldr.CheckSum = 0;
wm->ldr.TimeDateStamp = 0;
wm->ldr.ActivationContext = 0;
RtlCreateUnicodeString( &wm->ldr.FullDllName, filename );
if ((p = strrchrW( wm->ldr.FullDllName.Buffer, '\\' ))) p++;
......@@ -1031,10 +1054,7 @@ static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename )
&wm->ldr.InLoadOrderModuleList);
InsertTailList(&NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList,
&wm->ldr.InMemoryOrderModuleList);
/* wait until init is called for inserting into this list */
wm->ldr.InInitializationOrderModuleList.Flink = NULL;
wm->ldr.InInitializationOrderModuleList.Blink = NULL;
/* wait until init is called for inserting into InInitializationOrderModuleList */
if (!(nt->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT))
{
......@@ -1840,7 +1860,7 @@ static BOOL is_valid_binary( HMODULE module, const pe_image_info_t *info )
* load_native_dll (internal)
*/
static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file,
DWORD flags, WINE_MODREF** pwm )
DWORD flags, WINE_MODREF** pwm, struct stat *st )
{
void *module;
HANDLE mapping;
......@@ -1889,6 +1909,8 @@ static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file,
return STATUS_NO_MEMORY;
}
wm->dev = st->st_dev;
wm->ino = st->st_ino;
if (image_info.loader_flags) wm->ldr.Flags |= LDR_COR_IMAGE;
if (image_info.image_flags & IMAGE_FLAGS_ComPlusILOnly) wm->ldr.Flags |= LDR_COR_ILONLY;
......@@ -2170,11 +2192,12 @@ done:
*
* Open a file for a new dll. Helper for find_dll_file.
*/
static HANDLE open_dll_file( UNICODE_STRING *nt_name, WINE_MODREF **pwm )
static HANDLE open_dll_file( UNICODE_STRING *nt_name, WINE_MODREF **pwm, struct stat *st )
{
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK io;
HANDLE handle;
int fd, needs_close;
attr.Length = sizeof(attr);
attr.RootDirectory = 0;
......@@ -2186,6 +2209,18 @@ static HANDLE open_dll_file( UNICODE_STRING *nt_name, WINE_MODREF **pwm )
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE ))
return 0;
if (!server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))
{
fstat( fd, st );
if (needs_close) close( fd );
if ((*pwm = find_fileid_module( handle, st )))
{
TRACE( "%s is the same file as existing module %p %s\n", debugstr_w( nt_name->Buffer ),
(*pwm)->ldr.BaseAddress, debugstr_w( (*pwm)->ldr.FullDllName.Buffer ));
NtClose( handle );
return 0;
}
}
return handle;
}
......@@ -2196,7 +2231,8 @@ static HANDLE open_dll_file( UNICODE_STRING *nt_name, WINE_MODREF **pwm )
* Find the file (or already loaded module) for a given dll name.
*/
static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname,
WCHAR *filename, ULONG *size, WINE_MODREF **pwm, HANDLE *handle )
WCHAR *filename, ULONG *size, WINE_MODREF **pwm,
HANDLE *handle, struct stat *st )
{
UNICODE_STRING nt_name;
WCHAR *file_part, *ext, *dllname;
......@@ -2204,6 +2240,7 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname,
/* first append .dll if needed */
*handle = 0;
dllname = NULL;
if (!(ext = strrchrW( libname, '.')) || strchrW( ext, '/' ) || strchrW( ext, '\\'))
{
......@@ -2245,14 +2282,14 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname,
if (len)
{
if (len >= *size) goto overflow;
if ((*pwm = find_fullname_module( filename )) || !handle) goto found;
if ((*pwm = find_fullname_module( filename ))) goto found;
if (!RtlDosPathNameToNtPathName_U( filename, &nt_name, NULL, NULL ))
{
RtlFreeHeap( GetProcessHeap(), 0, dllname );
return STATUS_NO_MEMORY;
}
*handle = open_dll_file( &nt_name, pwm );
*handle = open_dll_file( &nt_name, pwm, st );
goto found;
}
......@@ -2279,8 +2316,8 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname,
len = nt_name.Length - 4*sizeof(WCHAR); /* for \??\ prefix */
if (len >= *size) goto overflow;
memcpy( filename, nt_name.Buffer + 4, len + sizeof(WCHAR) );
if (!(*pwm = find_fullname_module( filename )) && handle)
*handle = open_dll_file( &nt_name, pwm );
if (!(*pwm = find_fullname_module( filename )))
*handle = open_dll_file( &nt_name, pwm, st );
found:
RtlFreeUnicodeString( &nt_name );
......@@ -2308,7 +2345,8 @@ static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_
WCHAR *filename;
ULONG size;
WINE_MODREF *main_exe;
HANDLE handle = 0;
struct stat st;
HANDLE handle;
NTSTATUS nts;
TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) );
......@@ -2318,7 +2356,7 @@ static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_
size = sizeof(buffer);
for (;;)
{
nts = find_dll_file( load_path, libname, filename, &size, pwm, &handle );
nts = find_dll_file( load_path, libname, filename, &size, pwm, &handle, &st );
if (nts == STATUS_SUCCESS) break;
if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
if (nts != STATUS_BUFFER_TOO_SMALL) return nts;
......@@ -2360,7 +2398,7 @@ static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_
if (!handle) nts = STATUS_DLL_NOT_FOUND;
else
{
nts = load_native_dll( load_path, filename, handle, flags, pwm );
nts = load_native_dll( load_path, filename, handle, flags, pwm, &st );
if (nts == STATUS_INVALID_IMAGE_NOT_MZ)
/* not in PE format, maybe it's a builtin */
nts = load_builtin_dll( load_path, filename, handle, flags, pwm );
......@@ -2385,7 +2423,7 @@ static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_
nts = STATUS_DLL_NOT_FOUND;
}
if (nts == STATUS_DLL_NOT_FOUND && loadorder != LO_BUILTIN)
nts = load_native_dll( load_path, filename, handle, flags, pwm );
nts = load_native_dll( load_path, filename, handle, flags, pwm, &st );
break;
}
......@@ -2446,6 +2484,8 @@ NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_S
WCHAR *filename;
ULONG size;
WINE_MODREF *wm;
HANDLE handle;
struct stat st;
RtlEnterCriticalSection( &loader_section );
......@@ -2455,7 +2495,8 @@ NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_S
size = sizeof(buffer);
for (;;)
{
status = find_dll_file( load_path, name->Buffer, filename, &size, &wm, NULL );
status = find_dll_file( load_path, name->Buffer, filename, &size, &wm, &handle, &st );
if (handle) NtClose( handle );
if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
if (status != STATUS_BUFFER_TOO_SMALL) break;
/* grow the buffer and retry */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment