* 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:
		| @@ -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. | ||||||
|   | |||||||
| @@ -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; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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 (); | ||||||
| }; | }; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user