* dll_init.cc: Revert pathname changes from 2012-02-08.
(dll_list::operator[]): Add long comment to explain the misery. (dll_list::alloc): Skip long pathname prefix potentially returned by GetModuleFileNameW. * dll_init.h (dll_list::find_by_modname): Add back declaration.
This commit is contained in:
parent
cd78c479f4
commit
50124fc056
|
@ -1,3 +1,11 @@
|
||||||
|
2012-03-04 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
|
* dll_init.cc: Revert pathname changes from 2012-02-08.
|
||||||
|
(dll_list::operator[]): Add long comment to explain the misery.
|
||||||
|
(dll_list::alloc): Skip long pathname prefix potentially returned by
|
||||||
|
GetModuleFileNameW.
|
||||||
|
* dll_init.h (dll_list::find_by_modname): Add back declaration.
|
||||||
|
|
||||||
2012-03-04 Corinna Vinschen <corinna@vinschen.de>
|
2012-03-04 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
* winver.rc: Bump copyright date.
|
* winver.rc: Bump copyright date.
|
||||||
|
|
|
@ -106,13 +106,46 @@ dll::init ()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look for a dll based on the basename.
|
/* Look for a dll based on the full path.
|
||||||
Only compare basenames for DLLs. Per MSDN, the Windows loader re-uses
|
|
||||||
the already loaded DLL, if the new DLL has the same basename as the
|
CV, 2012-03-04: Per MSDN, If a DLL with the same module name is already
|
||||||
already loaded DLL. It will not try to load the new DLL at all. See
|
loaded in memory, the system uses the loaded DLL, no matter which directory
|
||||||
http://msdn.microsoft.com/en-us/library/ms682586%28v=vs.85%29.aspx */
|
it is in. The system does not search for the DLL. See
|
||||||
|
http://msdn.microsoft.com/en-us/library/ms682586%28v=vs.85%29.aspx
|
||||||
|
|
||||||
|
On 2012-02-08 I interpreted "module name" as "basename". So the assumption
|
||||||
|
was that the Windows Loader does not load another DLL with the same basename,
|
||||||
|
if one such DLL is already loaded. Consequentially I changed the code so
|
||||||
|
that DLLs are only compared by basename.
|
||||||
|
|
||||||
|
This assumption was obviously wrong, as the perl dynaloader proves. It
|
||||||
|
loads multiple DLLs with the same basename into memory, just from different
|
||||||
|
locations. This mechanism is broken when only comparing basenames in the
|
||||||
|
below code.
|
||||||
|
|
||||||
|
However, the original problem reported on 2012-02-07 was a result of
|
||||||
|
a subtil difference between the paths returned by different calls to
|
||||||
|
GetModuleFileNameW: Sometimes the path is a plain DOS path, sometimes
|
||||||
|
it's preceeded by the long pathname prefix "\\?\".
|
||||||
|
|
||||||
|
So I reverted the original change from 2012-02-08 and only applied the
|
||||||
|
following fix: Check if the path is preceeded by a long pathname prefix,
|
||||||
|
and, if so, drop it forthwith so that subsequent full path comparisons
|
||||||
|
work as expected. */
|
||||||
dll *
|
dll *
|
||||||
dll_list::operator[] (const PWCHAR modname)
|
dll_list::operator[] (const PWCHAR name)
|
||||||
|
{
|
||||||
|
dll *d = &start;
|
||||||
|
while ((d = d->next) != NULL)
|
||||||
|
if (!wcscasecmp (name, d->name))
|
||||||
|
return d;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Look for a dll based on the basename. */
|
||||||
|
dll *
|
||||||
|
dll_list::find_by_modname (const PWCHAR modname)
|
||||||
{
|
{
|
||||||
dll *d = &start;
|
dll *d = &start;
|
||||||
while ((d = d->next) != NULL)
|
while ((d = d->next) != NULL)
|
||||||
|
@ -128,21 +161,23 @@ dll_list::operator[] (const PWCHAR modname)
|
||||||
dll *
|
dll *
|
||||||
dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
|
dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
|
||||||
{
|
{
|
||||||
WCHAR name[NT_MAX_PATH];
|
WCHAR buf[NT_MAX_PATH];
|
||||||
GetModuleFileNameW (h, name, sizeof (name));
|
GetModuleFileNameW (h, buf, sizeof (buf));
|
||||||
|
PWCHAR name = buf;
|
||||||
|
if (!wcsncmp (name, L"\\\\?\\", 4))
|
||||||
|
name += 4;
|
||||||
DWORD namelen = wcslen (name);
|
DWORD namelen = wcslen (name);
|
||||||
PWCHAR modname = wcsrchr (name, L'\\') + 1;
|
|
||||||
|
|
||||||
guard (true);
|
guard (true);
|
||||||
/* Already loaded? */
|
/* Already loaded? */
|
||||||
dll *d = dlls[modname];
|
dll *d = dlls[name];
|
||||||
if (d)
|
if (d)
|
||||||
{
|
{
|
||||||
if (!in_forkee)
|
if (!in_forkee)
|
||||||
d->count++; /* Yes. Bump the usage count. */
|
d->count++; /* Yes. Bump the usage count. */
|
||||||
else if (d->handle != h)
|
else if (d->handle != h)
|
||||||
fabort ("%W: Loaded to different address: parent(%p) != child(%p)",
|
fabort ("%W: Loaded to different address: parent(%p) != child(%p)",
|
||||||
modname, d->handle, h);
|
name, d->handle, h);
|
||||||
d->p = p;
|
d->p = p;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -154,7 +189,7 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
|
||||||
supplied info about this DLL. */
|
supplied info about this DLL. */
|
||||||
d->count = 1;
|
d->count = 1;
|
||||||
wcscpy (d->name, name);
|
wcscpy (d->name, name);
|
||||||
d->modname = d->name + (modname - name);
|
d->modname = wcsrchr (d->name, L'\\') + 1;
|
||||||
d->handle = h;
|
d->handle = h;
|
||||||
d->has_dtors = true;
|
d->has_dtors = true;
|
||||||
d->p = p;
|
d->p = p;
|
||||||
|
@ -200,7 +235,7 @@ void dll_list::populate_deps (dll* d)
|
||||||
{
|
{
|
||||||
char* modname = pef->rva (id->Name);
|
char* modname = pef->rva (id->Name);
|
||||||
sys_mbstowcs (wmodname, NT_MAX_PATH, modname);
|
sys_mbstowcs (wmodname, NT_MAX_PATH, modname);
|
||||||
if (dll* dep = dlls[wmodname])
|
if (dll* dep = find_by_modname (wmodname))
|
||||||
{
|
{
|
||||||
if (d->ndeps >= maxdeps)
|
if (d->ndeps >= maxdeps)
|
||||||
{
|
{
|
||||||
|
|
|
@ -90,6 +90,7 @@ public:
|
||||||
void load_after_fork (HANDLE);
|
void load_after_fork (HANDLE);
|
||||||
void reserve_space ();
|
void reserve_space ();
|
||||||
void load_after_fork_impl (HANDLE, dll* which, int retries);
|
void load_after_fork_impl (HANDLE, dll* which, int retries);
|
||||||
|
dll *find_by_modname (const PWCHAR name);
|
||||||
void populate_deps (dll* d);
|
void populate_deps (dll* d);
|
||||||
void topsort ();
|
void topsort ();
|
||||||
void topsort_visit (dll* d, bool goto_tail);
|
void topsort_visit (dll* d, bool goto_tail);
|
||||||
|
|
Loading…
Reference in New Issue