4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-02-21 00:07:36 +08:00

* dll_init.h (struct dll): Set size of name element to ANYSIZE_ARRAY.

* dll_init.cc: Fix formatting.
	(dll_list::alloc): Only allocate as much memory for struct dll as
	necessary for given DLL name.
	(dll_list::load_after_fork): Only read a single page of parent memory.
	Only read more if namelen indicates that it's necessary.
This commit is contained in:
Corinna Vinschen 2009-06-06 11:47:29 +00:00
parent 611fe46079
commit 1d95e198c1
3 changed files with 60 additions and 36 deletions

View File

@ -1,3 +1,12 @@
2009-06-06 Corinna Vinschen <corinna@vinschen.de>
* dll_init.h (struct dll): Set size of name element to ANYSIZE_ARRAY.
* dll_init.cc: Fix formatting.
(dll_list::alloc): Only allocate as much memory for struct dll as
necessary for given DLL name.
(dll_list::load_after_fork): Only read a single page of parent memory.
Only read more if namelen indicates that it's necessary.
2009-06-05 Dave Korn <dave.korn.cygwin@gmail.com> 2009-06-05 Dave Korn <dave.korn.cygwin@gmail.com>
* winbase.h (ilockexch): Fix asm constraints. * winbase.h (ilockexch): Fix asm constraints.

View File

@ -1,6 +1,7 @@
/* dll_init.cc /* dll_init.cc
Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
2007, 2008, 2009 Red Hat, Inc.
This software is a copyrighted work licensed under the terms of the This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for Cygwin license. Please consult the file "CYGWIN_LICENSE" for
@ -19,6 +20,7 @@ details. */
#include "pinfo.h" #include "pinfo.h"
#include "cygtls.h" #include "cygtls.h"
#include <wchar.h> #include <wchar.h>
#include <alloca.h>
extern void __stdcall check_sanity_and_sync (per_process *); extern void __stdcall check_sanity_and_sync (per_process *);
@ -108,6 +110,7 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
{ {
WCHAR name[NT_MAX_PATH]; WCHAR name[NT_MAX_PATH];
DWORD namelen = GetModuleFileNameW (h, name, sizeof (name)); DWORD namelen = GetModuleFileNameW (h, name, sizeof (name));
size_t d_size = sizeof (dll) + namelen * sizeof (WCHAR);
/* Already loaded? */ /* Already loaded? */
dll *d = dlls[name]; dll *d = dlls[name];
@ -144,8 +147,8 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
n = ((n - r) + s1.dwAllocationGranularity); n = ((n - r) + s1.dwAllocationGranularity);
/* First reserve the area of memory, then commit it. */ /* First reserve the area of memory, then commit it. */
if (VirtualAlloc ((void *) n, sizeof (dll), MEM_RESERVE, PAGE_READWRITE)) if (VirtualAlloc ((void *) n, d_size, MEM_RESERVE, PAGE_READWRITE))
d = (dll *) VirtualAlloc ((void *) n, sizeof (dll), MEM_COMMIT, d = (dll *) VirtualAlloc ((void *) n, d_size, MEM_COMMIT,
PAGE_READWRITE); PAGE_READWRITE);
if (d) if (d)
break; break;
@ -265,11 +268,12 @@ release_upto (const PWCHAR name, DWORD here)
else else
{ {
size = mb.RegionSize; size = mb.RegionSize;
if (!(mb.State == MEM_RESERVE && mb.AllocationProtect == PAGE_NOACCESS && if (!(mb.State == MEM_RESERVE && mb.AllocationProtect == PAGE_NOACCESS
(((void *) start < cygheap->user_heap.base && (((void *) start < cygheap->user_heap.base
|| (void *) start > cygheap->user_heap.top) && || (void *) start > cygheap->user_heap.top)
((void *) start < (void *) cygheap && ((void *) start < (void *) cygheap
|| (void *) start > (void *) ((char *) cygheap + CYGHEAPSIZE))))) || (void *) start
> (void *) ((char *) cygheap + CYGHEAPSIZE)))))
continue; continue;
if (!VirtualFree ((void *) start, 0, MEM_RELEASE)) if (!VirtualFree ((void *) start, 0, MEM_RELEASE))
api_fatal ("couldn't release memory %p(%d) for '%W' alignment, %E\n", api_fatal ("couldn't release memory %p(%d) for '%W' alignment, %E\n",
@ -277,72 +281,82 @@ release_upto (const PWCHAR name, DWORD here)
} }
} }
/* Reload DLLs after a fork. Iterates over the list of dynamically loaded DLLs /* Reload DLLs after a fork. Iterates over the list of dynamically loaded
and attempts to load them in the same place as they were loaded in the parent. */ DLLs and attempts to load them in the same place as they were loaded in
the parent. */
void void
dll_list::load_after_fork (HANDLE parent, dll *first) dll_list::load_after_fork (HANDLE parent, dll *first)
{ {
int try2 = 0; int try2 = 0;
dll d; dll *d = (dll *) alloca (sizeof (dll) + (NT_MAX_PATH - 1) * sizeof (WCHAR));
void *next = first; void *next = first;
while (next) while (next)
{ {
DWORD nb; DWORD nb;
/* Read the dll structure from the parent. */ /* Read 4K of the dll structure from the parent. A full page has
if (!ReadProcessMemory (parent, next, &d, sizeof (dll), &nb) || been allocated anyway and this covers most, if not all DLL paths.
nb != sizeof (dll)) Only if d->namelen indicates that more than 4K are required,
read them in a second step. */
if (!ReadProcessMemory (parent, next, d, getsystempagesize (), &nb)
|| nb != getsystempagesize ())
return;
size_t namelen = d->namelen * sizeof (WCHAR);
if (namelen >= getsystempagesize () - sizeof (dll)
&& (!ReadProcessMemory (parent, next, d->name, namelen, &nb)
|| nb != namelen))
return; return;
/* We're only interested in dynamically loaded dlls. /* We're only interested in dynamically loaded dlls.
Hopefully, this function wouldn't even have been called unless Hopefully, this function wouldn't even have been called unless
the parent had some of those. */ the parent had some of those. */
if (d.type == DLL_LOAD) if (d->type == DLL_LOAD)
{ {
bool unload = true; bool unload = true;
HMODULE h = LoadLibraryExW (d.name, NULL, DONT_RESOLVE_DLL_REFERENCES); HMODULE h = LoadLibraryExW (d->name, NULL,
DONT_RESOLVE_DLL_REFERENCES);
if (!h) if (!h)
system_printf ("can't reload %W", d.name); system_printf ("can't reload %W", d->name);
/* See if DLL will load in proper place. If so, free it and reload /* See if DLL will load in proper place. If so, free it and reload
it the right way. it the right way.
It sort of stinks that we can't invert the order of the FreeLibrary It sort of stinks that we can't invert the order of the
and LoadLibrary since Microsoft documentation seems to imply that that FreeLibrary and LoadLibrary since Microsoft documentation seems
should do what we want. However, since the library was loaded above, to imply that that should do what we want. However, since the
the second LoadLibrary does not execute it's startup code unless it library was loaded above, the second LoadLibrary does not execute
is first unloaded. */ it's startup code unless it is first unloaded. */
else if (h == d.handle) else if (h == d->handle)
{ {
if (unload) if (unload)
{ {
FreeLibrary (h); FreeLibrary (h);
LoadLibraryW (d.name); LoadLibraryW (d->name);
} }
} }
else if (try2) else if (try2)
api_fatal ("unable to remap %W to same address as parent(%p) != %p", api_fatal ("unable to remap %W to same address as parent(%p) != %p",
d.name, d.handle, h); d->name, d->handle, h);
else else
{ {
/* It loaded in the wrong place. Dunno why this happens but it always /* It loaded in the wrong place. Dunno why this happens but it
seems to happen when there are multiple DLLs attempting to load into always seems to happen when there are multiple DLLs attempting
the same address space. In the "forked" process, the second DLL always to load into the same address space. In the "forked" process,
loads into a different location. */ the second DLL always loads into a different location. */
FreeLibrary (h); FreeLibrary (h);
/* Block all of the memory up to the new load address. */ /* Block all of the memory up to the new load address. */
reserve_upto (d.name, (DWORD) d.handle); reserve_upto (d->name, (DWORD) d->handle);
try2 = 1; /* And try */ try2 = 1; /* And try */
continue; /* again. */ continue; /* again. */
} }
/* If we reached here, and try2 is set, then there is a lot of memory to /* If we reached here, and try2 is set, then there is a lot of
release. */ memory to release. */
if (try2) if (try2)
{ {
release_upto (d.name, (DWORD) d.handle); release_upto (d->name, (DWORD) d->handle);
try2 = 0; try2 = 0;
} }
} }
next = d.next; /* Get the address of the next DLL. */ next = d->next; /* Get the address of the next DLL. */
} }
in_forkee = false; in_forkee = false;
} }

View File

@ -1,6 +1,7 @@
/* dll_init.h /* dll_init.h
Copyright 1998, 1999, 2000, 2001 Red Hat, Inc. Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2007, 2008,
2009 Red Hat, Inc.
This file is part of Cygwin. This file is part of Cygwin.
@ -51,7 +52,7 @@ struct dll
int count; int count;
dll_type type; dll_type type;
int namelen; int namelen;
WCHAR name[NT_MAX_PATH]; WCHAR name[ANYSIZE_ARRAY];
void detach (); void detach ();
int init (); int init ();
}; };