# HG changeset patch # Parent 46e70d723c0744a79e7290b1c4bf9d0490b0a539 diff --git a/child_info.h b/child_info.h --- a/child_info.h +++ b/child_info.h @@ -92,6 +92,18 @@ void alloc_stack_hard_way (volatile char *); }; +/* Several well-known problems can prevent us from patching up a + forkee; when such errors arise the child should exit cleanly (with + a failure code for the parent) rather than dumping stack. */ +#define fork_api_fatal(fmt, args...) \ + do \ + { \ + sigproc_printf (fmt,## args); \ + fork_info->handle_failure (-1); \ + } \ + while(0) + + class fhandler_base; class cygheap_exec_info diff --git a/dll_init.cc b/dll_init.cc --- a/dll_init.cc +++ b/dll_init.cc @@ -19,6 +19,7 @@ #include "dtable.h" #include "cygheap.h" #include "pinfo.h" +#include "child_info.h" #include "cygtls.h" #include "exception.h" #include @@ -131,10 +132,16 @@ { if (!in_forkee) d->count++; /* Yes. Bump the usage count. */ + else if (d->handle != h) + fork_api_fatal ("Location of %W changed from %p (parent) to %p (child)", + d->name, d->handle, h); d->p = p; } else { + if (in_forkee) + system_printf ("Unexpected dll loaded during fork: %W", name); + /* FIXME: Change this to new at some point. */ d = (dll *) cmalloc (HEAP_2_DLL, sizeof (*d) + (namelen * sizeof (*name))); @@ -371,7 +378,6 @@ preferred_block = reserve_at (d->name, (DWORD) h); } - in_forkee = false; } struct dllcrt0_info diff --git a/dll_init.h b/dll_init.h --- a/dll_init.h +++ b/dll_init.h @@ -57,7 +57,7 @@ int init (); void run_dtors () { - if (has_dtors) + if (has_dtors && !in_forkee) { has_dtors = 0; p.run_dtors (); diff --git a/fork.cc b/fork.cc --- a/fork.cc +++ b/fork.cc @@ -233,6 +233,7 @@ sync_with_parent ("loaded dlls", true); } + in_forkee = false; init_console_handler (myself->ctty >= 0); ForceCloseHandle1 (fork_info->forker_finished, forker_finished); @@ -393,10 +394,13 @@ if (!exit_code) continue; this_errno = EAGAIN; - /* Not thread safe, but do we care? */ - __small_sprintf (errbuf, "died waiting for longjmp before initialization, " - "retry %d, exit code %p", ch.retry, exit_code); - error = errbuf; + if (exit_code != EXITCODE_FORK_FAILED) + { + /* Not thread safe, but do we care? */ + __small_sprintf (errbuf, "died waiting for longjmp before initialization, " + "retry %d, exit code %p", ch.retry, exit_code); + error = errbuf; + } goto cleanup; } break; @@ -515,7 +519,8 @@ if (!ch.sync (child->pid, pi.hProcess, FORK_WAIT_TIMEOUT)) { this_errno = EAGAIN; - error = "died waiting for dll loading"; + if (ch.exit_code != EXITCODE_FORK_FAILED) + error = "died waiting for dll loading"; goto cleanup; } diff --git a/heap.cc b/heap.cc --- a/heap.cc +++ b/heap.cc @@ -88,11 +88,11 @@ if ((reserve_size -= page_const) < allocsize) break; } - if (!p && in_forkee && !fork_info->handle_failure (GetLastError ())) - api_fatal ("couldn't allocate heap, %E, base %p, top %p, " - "reserve_size %d, allocsize %d, page_const %d", - cygheap->user_heap.base, cygheap->user_heap.top, - reserve_size, allocsize, page_const); + if (!p) + fork_api_fatal ("couldn't allocate heap, %E, base %p, top %p, " + "reserve_size %d, allocsize %d, page_const %d", + cygheap->user_heap.base, cygheap->user_heap.top, + reserve_size, allocsize, page_const); if (p != cygheap->user_heap.base) api_fatal ("heap allocated at wrong address %p (mapped) != %p (expected)", p, cygheap->user_heap.base); if (allocsize && !VirtualAlloc (cygheap->user_heap.base, allocsize, MEM_COMMIT, PAGE_READWRITE)) diff --git a/pinfo.h b/pinfo.h --- a/pinfo.h +++ b/pinfo.h @@ -36,6 +36,7 @@ #define EXITCODE_NOSET 0x4000000 #define EXITCODE_RETRY 0x2000000 #define EXITCODE_OK 0x1000000 +#define EXITCODE_FORK_FAILED 0x2200000 class fhandler_pipe; diff --git a/sigproc.cc b/sigproc.cc --- a/sigproc.cc +++ b/sigproc.cc @@ -914,6 +914,9 @@ if (retry-- > 0) exit_code = 0; break; + case EXITCODE_FORK_FAILED: /* windows prevented us from forking */ + break; + /* Count down non-recognized exit codes more quickly since they aren't due to known conditions. */ default: @@ -932,8 +935,13 @@ bool child_info_fork::handle_failure (DWORD err) { - if (retry > 0) + if (in_forkee && retry > 0) ExitProcess (EXITCODE_RETRY); + else + { + sigproc_printf ("Unable to fork."); + ExitProcess (EXITCODE_FORK_FAILED); + } return 0; }