public inbox for cygwin-patches@cygwin.com
 help / color / mirror / Atom feed
* Improvements to fork handling (5/5)
@ 2011-05-11 18:33 Ryan Johnson
  0 siblings, 0 replies; only message in thread
From: Ryan Johnson @ 2011-05-11 18:33 UTC (permalink / raw)
  To: cygwin-patches

[-- Attachment #1: Type: text/plain, Size: 685 bytes --]

Hi all,

This last patch adds a small optimization which reserves the lower 4MB 
of address space early in the process's lifetime (even if it's not a 
forkee). This was motivated by the observation that Windows tends to 
move things around a lot in that area, increasing the probability of 
future fork failures if the parent allows cygwin dlls to land there.  
The patch does not fully address the problem, however, because ASLR 
clobbers addresses above 4M as well. As a result, this patch may or may 
not improve fork success rates in practice: most fork failures for me 
involve DLL_LINK dlls which landed badly in the child.

It should be independent of the other patches.

Ryan


[-- Attachment #2: fork-bad-addr.patch --]
[-- Type: text/plain, Size: 2595 bytes --]

diff --git a/dcrt0.cc b/dcrt0.cc
--- a/dcrt0.cc
+++ b/dcrt0.cc
@@ -792,6 +792,13 @@ dll_crt0_1 (void *)
   main_vfork = vfork_storage.create ();
 #endif
 
+  /* Windows doesn't use the lower 4MB of address space consistently,
+     and those uses arise before cygwin1.dll loads. If a dll loads
+     there we risk being unable to fork later. To avoid the problem,
+     we just reserve everything that's left in that space -- windows
+     can still do what it wants since it got there first. */
+  dlls.block_bad_address_space ();
+  
   cygbench ("pre-forkee");
   if (in_forkee)
     {
diff --git a/dll_init.cc b/dll_init.cc
--- a/dll_init.cc
+++ b/dll_init.cc
@@ -359,6 +359,44 @@ dll_list::init ()
 #define A64K (64 * 1024)
 
 
+void
+dll_list::block_bad_address_space ()
+{
+  /* For some reason VirtualQuery doesn't return consistent values of
+     RegionSize for free space, so we have to compute it manually by
+     looking for MEM_FREE followed by a not-free region. We ensure not
+     to leave a danging free region by allowing the loop to examine
+     0x00400000, which is always the address of the application's
+     executable image.
+   */
+  MEMORY_BASIC_INFORMATION mb;
+  DWORD here;
+  for (DWORD i=A64K; i <= 64*A64K; i += mb.RegionSize)
+    {
+      if ( !VirtualQuery ((void*)i, &mb, sizeof(mb)))
+	api_fatal ("-> unable to examine address space at %08lx, %E", i);
+      here = (DWORD) mb.BaseAddress;
+      
+      /* this should never happen. If it does we'll need to write some
+	 code to compensate for it */
+      if (here != i)
+	api_fatal ("VirtualQuery returned info for %lx instead of %lx",
+		   here, i);
+      if (mb.State == MEM_FREE)
+	{
+	  DWORD size = mb.RegionSize;
+	  if (!VirtualAlloc ((void*) here, size, MEM_RESERVE, PAGE_NOACCESS))
+	    system_printf ("-> couldn't block out %08lx, %E", here);
+	}
+      else if (mb.RegionSize & (A64K-1))
+	{
+	  /* skip free space at the end of mapped slices -- they can't
+	     be used by anything else */
+	  mb.RegionSize = (mb.RegionSize + A64K - 1) & -A64K;
+	}
+    }
+}
+
 /* Reserve the chunk of free address space starting _here_ and (usually)
    covering at least _dll_size_ bytes. However, we must take care not
    to clobber the dll's target address range because it often overlaps.
diff --git a/dll_init.h b/dll_init.h
--- a/dll_init.h
+++ b/dll_init.h
@@ -83,6 +83,7 @@ public:
   int tot;
   int loaded_dlls;
   int reload_on_fork;
+  void block_bad_address_space ();
   dll *operator [] (const PWCHAR name);
   dll *alloc (HINSTANCE, per_process *, dll_type);
   dll *find (void *);

[-- Attachment #3: fork-bad-addr.changes --]
[-- Type: text/plain, Size: 369 bytes --]

        * dcrt0.cc (dll_crt0_1): call dll_list::block_bad_address_space
        * dll_init.cc (dll_list::block_bad_address_space): new function to
        reserve all free space in the low 4MB. Reduces somewhat the
        probability of a dynamic dll clashing with windows heaps or thread
        stacks.
        * dll_init.h (struct dll_list): declaration for above.

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2011-05-11 18:33 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-11 18:33 Improvements to fork handling (5/5) Ryan Johnson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).