* dll_init.cc (reserve_at, release_at): New functions.
(load_after_fork): If the DLL was loaded higher than the required address, assume that it loaded at it's base address and also reserve memory there to force it to be relocated.
This commit is contained in:
parent
641965646a
commit
8d777a13fc
@ -1,3 +1,10 @@
|
|||||||
|
2011-04-06 Jon TURNEY <jon.turney@dronecode.org.uk>
|
||||||
|
|
||||||
|
* dll_init.cc (reserve_at, release_at): New functions.
|
||||||
|
(load_after_fork): If the DLL was loaded higher than the required
|
||||||
|
address, assume that it loaded at it's base address and also reserve
|
||||||
|
memory there to force it to be relocated.
|
||||||
|
|
||||||
2011-04-04 Yaakov Selkowitz <yselkowitz@users.sourceforge.net>
|
2011-04-04 Yaakov Selkowitz <yselkowitz@users.sourceforge.net>
|
||||||
|
|
||||||
* include/cygwin/types.h: Move #include <sys/sysmacros.h> to
|
* include/cygwin/types.h: Move #include <sys/sysmacros.h> to
|
||||||
|
@ -78,7 +78,7 @@ dll::init ()
|
|||||||
/* This should be a no-op. Why didn't we just import this variable? */
|
/* This should be a no-op. Why didn't we just import this variable? */
|
||||||
if (!p.envptr)
|
if (!p.envptr)
|
||||||
p.envptr = &__cygwin_environ;
|
p.envptr = &__cygwin_environ;
|
||||||
else
|
else if (*(p.envptr) != __cygwin_environ)
|
||||||
*(p.envptr) = __cygwin_environ;
|
*(p.envptr) = __cygwin_environ;
|
||||||
|
|
||||||
/* Don't run constructors or the "main" if we've forked. */
|
/* Don't run constructors or the "main" if we've forked. */
|
||||||
@ -257,12 +257,44 @@ release_upto (const PWCHAR name, DWORD here)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mark one page at "here" as reserved. This may force
|
||||||
|
Windows NT to load a DLL elsewhere. */
|
||||||
|
static DWORD
|
||||||
|
reserve_at (const PWCHAR name, DWORD here)
|
||||||
|
{
|
||||||
|
DWORD size;
|
||||||
|
MEMORY_BASIC_INFORMATION mb;
|
||||||
|
|
||||||
|
if (!VirtualQuery ((void *) here, &mb, sizeof (mb)))
|
||||||
|
size = 64 * 1024;
|
||||||
|
|
||||||
|
if (mb.State != MEM_FREE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
size = mb.RegionSize;
|
||||||
|
if (!VirtualAlloc ((void *) here, size, MEM_RESERVE, PAGE_NOACCESS))
|
||||||
|
api_fatal ("couldn't allocate memory %p(%d) for '%W' alignment, %E\n",
|
||||||
|
here, size, name);
|
||||||
|
return here;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the memory previously allocated by "reserve_at" above. */
|
||||||
|
static void
|
||||||
|
release_at (const PWCHAR name, DWORD here)
|
||||||
|
{
|
||||||
|
if (!VirtualFree ((void *) here, 0, MEM_RELEASE))
|
||||||
|
api_fatal ("couldn't release memory %p for '%W' alignment, %E\n",
|
||||||
|
here, name);
|
||||||
|
}
|
||||||
|
|
||||||
/* Reload DLLs after a fork. Iterates over the list of dynamically loaded
|
/* Reload DLLs after a fork. Iterates over the list of dynamically loaded
|
||||||
DLLs and attempts to load them in the same place as they were loaded in the
|
DLLs and attempts to load them in the same place as they were loaded in the
|
||||||
parent. */
|
parent. */
|
||||||
void
|
void
|
||||||
dll_list::load_after_fork (HANDLE parent)
|
dll_list::load_after_fork (HANDLE parent)
|
||||||
{
|
{
|
||||||
|
DWORD preferred_block = 0;
|
||||||
|
|
||||||
for (dll *d = &dlls.start; (d = d->next) != NULL; )
|
for (dll *d = &dlls.start; (d = d->next) != NULL; )
|
||||||
if (d->type == DLL_LOAD)
|
if (d->type == DLL_LOAD)
|
||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
@ -284,10 +316,18 @@ dll_list::load_after_fork (HANDLE parent)
|
|||||||
if (h == d->handle)
|
if (h == d->handle)
|
||||||
h = LoadLibraryW (d->name);
|
h = LoadLibraryW (d->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we reached here on the second iteration of the for loop
|
/* If we reached here on the second iteration of the for loop
|
||||||
then there is a lot of memory to release. */
|
then there is a lot of memory to release. */
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
|
{
|
||||||
release_upto (d->name, (DWORD) d->handle);
|
release_upto (d->name, (DWORD) d->handle);
|
||||||
|
|
||||||
|
if (preferred_block)
|
||||||
|
release_at (d->name, preferred_block);
|
||||||
|
preferred_block = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (h == d->handle)
|
if (h == d->handle)
|
||||||
break; /* Success */
|
break; /* Success */
|
||||||
|
|
||||||
@ -297,11 +337,20 @@ dll_list::load_after_fork (HANDLE parent)
|
|||||||
d->name, d->handle, h);
|
d->name, d->handle, h);
|
||||||
|
|
||||||
/* Dll loaded in the wrong place. Dunno why this happens but it
|
/* Dll loaded in the wrong place. Dunno why this happens but it
|
||||||
always seems to happen when there are multiple DLLs attempting to
|
always seems to happen when there are multiple DLLs with the
|
||||||
load into the same address space. In the "forked" process, the
|
same base address. In the "forked" process, the relocated DLL
|
||||||
second DLL always loads into a different location. So, block all
|
may load at a different address. So, block all of the memory up
|
||||||
of the memory up to the new load address and try again. */
|
to the relocated load address and try again. */
|
||||||
reserve_upto (d->name, (DWORD) d->handle);
|
reserve_upto (d->name, (DWORD) d->handle);
|
||||||
|
|
||||||
|
/* Also, if the DLL loaded at a higher address than wanted (probably
|
||||||
|
it's base address), reserve the memory at that address. This can
|
||||||
|
happen if it couldn't load at the preferred base in the parent, but
|
||||||
|
can in the child, due to differences in the load ordering.
|
||||||
|
Block memory at it's preferred address and try again. */
|
||||||
|
if ((DWORD) h > (DWORD) d->handle)
|
||||||
|
preferred_block = reserve_at (d->name, (DWORD) h);
|
||||||
|
|
||||||
}
|
}
|
||||||
in_forkee = false;
|
in_forkee = false;
|
||||||
}
|
}
|
||||||
@ -431,6 +480,7 @@ void __stdcall
|
|||||||
update_envptrs ()
|
update_envptrs ()
|
||||||
{
|
{
|
||||||
for (dll *d = dlls.istart (DLL_ANY); d; d = dlls.inext ())
|
for (dll *d = dlls.istart (DLL_ANY); d; d = dlls.inext ())
|
||||||
|
if (*(d->p.envptr) != __cygwin_environ)
|
||||||
*(d->p.envptr) = __cygwin_environ;
|
*(d->p.envptr) = __cygwin_environ;
|
||||||
*main_environ = __cygwin_environ;
|
*main_environ = __cygwin_environ;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user