* dll_init.cc (dll_list::alloc): Initialize dll::image_size.

(reserve_at): Don't reserve space needed by the target dll if the latter
overlaps the free region to be blocked.
(dll_list::load_after_fork): Use new version of reserve_at.
* dll_init.h (dll::image_size): New member.
(pefile): New struct.
This commit is contained in:
Christopher Faylor 2011-05-28 20:55:34 +00:00
parent 07f89f85db
commit 6cd2e18523
3 changed files with 48 additions and 6 deletions

View File

@ -1,3 +1,12 @@
2011-05-28 Ryan Johnson <ryan.johnson@cs.utoronto.ca>
* dll_init.cc (dll_list::alloc): Initialize dll::image_size.
(reserve_at): Don't reserve space needed by the target dll if the
latter overlaps the free region to be blocked.
(dll_list::load_after_fork): Use new version of reserve_at.
* dll_init.h (dll::image_size): New member.
(pefile): New struct.
2011-05-28 Christopher Faylor <me.cygwin2011@cgf.cx> 2011-05-28 Christopher Faylor <me.cygwin2011@cgf.cx>
Ryan Johnson <ryan.johnson@cs.utoronto.ca> Ryan Johnson <ryan.johnson@cs.utoronto.ca>

View File

@ -161,6 +161,7 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
d->handle = h; d->handle = h;
d->has_dtors = true; d->has_dtors = true;
d->p = p; d->p = p;
d->image_size = ((pefile*)h)->optional_hdr ()->SizeOfImage;
d->type = type; d->type = type;
if (end == NULL) if (end == NULL)
end = &start; /* Point to "end" of dll chain. */ end = &start; /* Point to "end" of dll chain. */
@ -292,21 +293,33 @@ release_upto (const PWCHAR name, DWORD here)
} }
} }
/* Mark one page at "here" as reserved. This may force /* Reserve the chunk of free address space starting _here_ and (usually)
Windows NT to load a DLL elsewhere. */ covering at least _dll_size_ bytes. However, we must take care not
to clobber the dll's target address range because it often overlaps.
*/
static DWORD static DWORD
reserve_at (const PWCHAR name, DWORD here) reserve_at (const PWCHAR name, DWORD here, DWORD dll_base, DWORD dll_size)
{ {
DWORD size; DWORD size;
MEMORY_BASIC_INFORMATION mb; MEMORY_BASIC_INFORMATION mb;
if (!VirtualQuery ((void *) here, &mb, sizeof (mb))) if (!VirtualQuery ((void *) here, &mb, sizeof (mb)))
size = 64 * 1024; api_fatal ("couldn't examine memory at %08lx while mapping %W, %E",
here, name);
if (mb.State != MEM_FREE) if (mb.State != MEM_FREE)
return 0; return 0;
size = mb.RegionSize; size = mb.RegionSize;
// don't clobber the space where we want the dll to land
DWORD end = here + size;
DWORD dll_end = dll_base + dll_size;
if (dll_base < here && dll_end > here)
here = dll_end; // the dll straddles our left edge
else if (dll_base >= here && dll_base < end)
end = dll_base; // the dll overlaps partly or fully to our right
size = end - here;
if (!VirtualAlloc ((void *) here, size, MEM_RESERVE, PAGE_NOACCESS)) if (!VirtualAlloc ((void *) here, size, MEM_RESERVE, PAGE_NOACCESS))
api_fatal ("couldn't allocate memory %p(%d) for '%W' alignment, %E\n", api_fatal ("couldn't allocate memory %p(%d) for '%W' alignment, %E\n",
here, size, name); here, size, name);
@ -384,7 +397,8 @@ dll_list::load_after_fork (HANDLE parent)
can in the child, due to differences in the load ordering. can in the child, due to differences in the load ordering.
Block memory at it's preferred address and try again. */ Block memory at it's preferred address and try again. */
if ((DWORD) h > (DWORD) d->handle) if ((DWORD) h > (DWORD) d->handle)
preferred_block = reserve_at (d->name, (DWORD) h); preferred_block = reserve_at (d->name, (DWORD) h,
(DWORD) d->handle, d->image_size);
} }
} }

View File

@ -52,6 +52,7 @@ struct dll
int count; int count;
bool has_dtors; bool has_dtors;
dll_type type; dll_type type;
DWORD image_size;
WCHAR name[1]; WCHAR name[1];
void detach (); void detach ();
int init (); int init ();
@ -109,6 +110,24 @@ public:
dll_list () { protect.init ("dll_list"); } dll_list () { protect.init ("dll_list"); }
}; };
/* References:
http://msdn.microsoft.com/en-us/windows/hardware/gg463125
http://msdn.microsoft.com/en-us/library/ms809762.aspx
*/
struct pefile
{
IMAGE_DOS_HEADER dos_hdr;
char* rva (long offset) { return (char*) this + offset; }
PIMAGE_NT_HEADERS32 pe_hdr () { return (PIMAGE_NT_HEADERS32) rva (dos_hdr.e_lfanew); }
PIMAGE_OPTIONAL_HEADER32 optional_hdr () { return &pe_hdr ()->OptionalHeader; }
PIMAGE_DATA_DIRECTORY idata_dir (DWORD which)
{
PIMAGE_OPTIONAL_HEADER32 oh = optional_hdr ();
return (which < oh->NumberOfRvaAndSizes)? oh->DataDirectory + which : 0;
}
};
extern dll_list dlls; extern dll_list dlls;
void dll_global_dtors (); void dll_global_dtors ();