Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/ChangeLog23
-rw-r--r--winsup/cygwin/child_info.h11
-rw-r--r--winsup/cygwin/cygheap.cc4
-rw-r--r--winsup/cygwin/dcrt0.cc5
-rw-r--r--winsup/cygwin/debug.cc4
-rw-r--r--winsup/cygwin/dtable.cc4
-rw-r--r--winsup/cygwin/exceptions.cc2
-rw-r--r--winsup/cygwin/fork.cc727
-rw-r--r--winsup/cygwin/heap.cc1
-rw-r--r--winsup/cygwin/path.cc3
-rw-r--r--winsup/cygwin/security.cc2
-rw-r--r--winsup/cygwin/sigproc.cc4
-rw-r--r--winsup/cygwin/strace.cc16
13 files changed, 407 insertions, 399 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 6cd667b3b..40d7d7072 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,26 @@
+Thu Oct 12 17:58:03 2000 Christopher Faylor <cgf@cygnus.com>
+
+ * child_info: Bump child_info "version".
+ (child_info): Move some fields from child_info_spawn to here.
+ * cygheap.cc: Make cygheap pointers NOCOPY.
+ * dcrt0.cc (dll_crt0_1): Copy cygwin heap here regardless of whether
+ we've been forked or execed.
+ * dtable.cc (dtable::fixup_after_fork): Just release close-on-exec fds.
+ * exceptions.cc (stackdump): Respond to C warning.
+ * fork.cc: Reorganize to minimize stack copying.
+ (fork_child): New function.
+ (fork_parent): Ditto.
+ (sync_with_child): Don't suspend the forkee.
+ (sync_with_parent): Ditto. Make into a function.
+ * heap.cc (heap_init): Add some debugging output.
+ * path.cc (path_conv::check): Add an assertion.
+ (has_suffix): Ditto.
+ * security.cc (get_pw_sid): Defend against NULL.
+ * sigproc.cc (proc_subproc): Fix debugging output.
+ (wait_sig): Ditto.
+ * strace.cc: Make statics NO_COPY throughout.
+ (strace::vsprntf): Defend against NULL.
+
Thu Oct 12 00:25:29 2000 Christopher Faylor <cgf@cygnus.com>
* errno.cc (seterrno_from_win_error): Fix debugging output.
diff --git a/winsup/cygwin/child_info.h b/winsup/cygwin/child_info.h
index afea34b02..b3018c67b 100644
--- a/winsup/cygwin/child_info.h
+++ b/winsup/cygwin/child_info.h
@@ -12,7 +12,7 @@ details. */
enum
{
- PROC_MAGIC = 0xaf08f000,
+ PROC_MAGIC = 0xaf09f000,
PROC_FORK = PROC_MAGIC + 1,
PROC_EXEC = PROC_MAGIC + 2,
PROC_SPAWN = PROC_MAGIC + 3,
@@ -37,6 +37,9 @@ public:
HANDLE shared_h;
HANDLE console_h;
HANDLE parent_alive; // handle of thread used to track children
+ HANDLE parent;
+ void *cygheap;
+ void *cygheap_max;
};
class child_info_fork: public child_info
@@ -72,13 +75,9 @@ public:
class child_info_spawn: public child_info
{
public:
- HANDLE parent;
- void *cygheap;
- void *cygheap_max;
cygheap_exec_info *moreinfo;
- child_info_spawn (): parent (NULL), cygheap (NULL),
- cygheap_max (NULL), moreinfo (NULL) {}
+ child_info_spawn (): moreinfo (NULL) {}
~child_info_spawn ()
{
if (parent)
diff --git a/winsup/cygwin/cygheap.cc b/winsup/cygwin/cygheap.cc
index e71c94d0e..ee686fac4 100644
--- a/winsup/cygwin/cygheap.cc
+++ b/winsup/cygwin/cygheap.cc
@@ -18,8 +18,8 @@
#include "cygerrno.h"
#include "sync.h"
-void *cygheap = NULL;
-void *cygheap_max = NULL;
+void NO_COPY *cygheap = NULL;
+void NO_COPY *cygheap_max = NULL;
static NO_COPY muto *cygheap_protect = NULL;
diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc
index 05f5a8d48..4c8b42879 100644
--- a/winsup/cygwin/dcrt0.cc
+++ b/winsup/cygwin/dcrt0.cc
@@ -662,10 +662,13 @@ dll_crt0_1 ()
if (child_proc_info)
{
+ cygheap = child_proc_info->cygheap;
+ cygheap_max = child_proc_info->cygheap_max;
switch (child_proc_info->type)
{
case PROC_FORK:
case PROC_FORK1:
+ cygheap_fixup_in_child (child_proc_info->parent, 0);
alloc_stack (fork_info);
set_myself (mypid);
user_data->forkee = child_proc_info->cygpid;
@@ -677,8 +680,6 @@ dll_crt0_1 ()
case PROC_EXEC:
case PROC_SPAWN:
HANDLE h;
- cygheap = spawn_info->cygheap;
- cygheap_max = spawn_info->cygheap_max;
cygheap_fixup_in_child (spawn_info->parent, 1);
if (!spawn_info->moreinfo->myself_pinfo ||
!DuplicateHandle (hMainProc, spawn_info->moreinfo->myself_pinfo,
diff --git a/winsup/cygwin/debug.cc b/winsup/cygwin/debug.cc
index f96660c51..8ab767c31 100644
--- a/winsup/cygwin/debug.cc
+++ b/winsup/cygwin/debug.cc
@@ -306,6 +306,10 @@ close_handle (const char *func, int ln, HANDLE h, const char *name, BOOL force)
}
unlock_debug ();
+#if 0 /* Uncomment to see CloseHandle failures */
+ if (!ret)
+ small_printf ("CloseHandle(%s) failed %s:%d\n", name, func, ln);
+#endif
return ret;
}
#endif /*DEBUGGING*/
diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index f149d562b..ec05498f8 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -472,7 +472,9 @@ dtable::fixup_after_fork (HANDLE parent)
for (size_t i = 0; i < size; i++)
if ((fh = fds[i]) != NULL)
{
- if (fh->get_close_on_exec () || fh->get_need_fork_fixup ())
+ if (fds[i]->get_close_on_exec ())
+ release (i);
+ else if (fh->get_need_fork_fixup ())
{
debug_printf ("fd %d(%s)", i, fh->get_name ());
fh->fixup_after_fork (parent);
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index b536d6685..6f838ee7f 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -385,7 +385,7 @@ try_to_debug ()
static void
stackdump (EXCEPTION_RECORD *e, CONTEXT *in)
{
- char *p;
+ const char *p;
if (myself->progname[0])
{
/* write to progname.stackdump if possible */
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index ae4ee890b..82047795d 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -173,447 +173,387 @@ sync_with_child (PROCESS_INFORMATION &pi, HANDLE subproc_ready,
}
debug_printf ("child signalled me");
- if (hang_child)
- {
- int n = SuspendThread (pi.hThread);
- debug_printf ("suspend count %d", n); \
- }
return 1;
}
static int
resume_child (PROCESS_INFORMATION &pi, HANDLE forker_finished)
{
- int rc;
-
- debug_printf ("here");
SetEvent (forker_finished);
-
- rc = ResumeThread (pi.hThread);
-
- debug_printf ("rc %d", rc);
- if (rc == 1)
- return 1; // Successful resumption
-
- /* Can't resume the thread. Not sure why this would happen unless
- there's a bug in the system. Things seem to be working OK now
- though, so flag this with EAGAIN, but print a message on the
- console. */
- small_printf ("fork: ResumeThread failed, rc = %d, %E\n", rc);
- set_errno (EAGAIN);
- syscall_printf ("-1 = fork(), ResumeThread failed");
- TerminateProcess (pi.hProcess, 1);
- return 0;
+ debug_printf ("signalled child");
+ return 1;
}
/* Notify parent that it is time for the next step.
Note that this has to be a macro since the parent may be messing with
our stack. */
-#define sync_with_parent(s, hang_self) \
-((void) ({ \
- debug_printf ("signalling parent: %s", s); \
- /* Tell our parent we're waiting. */ \
- if (!SetEvent (child_proc_info->subproc_ready)) \
- api_fatal ("fork child - SetEvent failed, %E"); \
- if (hang_self) \
- { \
- /* Wait for the parent to fill in our stack and heap. \
- Don't wait forever here. If our parent dies we don't want to clog \
- the system. If the wait fails, we really can't continue so exit. */ \
- DWORD psync_rc = WaitForSingleObject (child_proc_info->forker_finished, FORK_WAIT_TIMEOUT); \
- switch (psync_rc) \
- { \
- case WAIT_TIMEOUT: \
- api_fatal ("sync_with_parent - WFSO timed out"); \
- break; \
- case WAIT_FAILED: \
- if (GetLastError () == ERROR_INVALID_HANDLE && \
- WaitForSingleObject (child_proc_info->forker_finished, 1) != WAIT_FAILED) \
- break; \
- api_fatal ("sync_with_parent - WFSO failed, fork_finished %p, %E", child_proc_info->forker_finished); \
- break; \
- default: \
- break; \
- } \
- debug_printf ("awake"); \
- } \
- 0; \
-}))
-
-static volatile void grow_stack_slack();
-
-static void *
-stack_dummy (int here)
+static void __stdcall
+sync_with_parent(const char *s, bool hang_self)
{
- return &here;
+ debug_printf ("signalling parent: %s", s);
+ /* Tell our parent we're waiting. */
+ if (!SetEvent (child_proc_info->subproc_ready))
+ api_fatal ("fork child - SetEvent failed, %E");
+ if (hang_self)
+ {
+ HANDLE h = child_proc_info->forker_finished;
+ /* Wait for the parent to fill in our stack and heap.
+ Don't wait forever here. If our parent dies we don't want to clog
+ the system. If the wait fails, we really can't continue so exit. */
+ DWORD psync_rc = WaitForSingleObject (h, FORK_WAIT_TIMEOUT);
+ debug_printf ("awake");
+ switch (psync_rc)
+ {
+ case WAIT_TIMEOUT:
+ api_fatal ("WFSO timed out");
+ break;
+ case WAIT_FAILED:
+ if (GetLastError () == ERROR_INVALID_HANDLE &&
+ WaitForSingleObject (child_proc_info->forker_finished, 1) != WAIT_FAILED)
+ break;
+ api_fatal ("WFSO failed, fork_finished %p, %E", child_proc_info->forker_finished);
+ break;
+ default:
+ debug_printf ("no problems");
+ break;
+ }
+ }
}
-extern "C" int
-fork ()
+static int __stdcall
+fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls)
{
- int res;
- DWORD rc;
- HANDLE hParent;
- HANDLE subproc_ready, forker_finished;
- void *stack_here;
- int x;
- PROCESS_INFORMATION pi = {0, NULL, 0, 0};
- static NO_COPY HANDLE last_fork_proc = NULL;
+ debug_printf ("child is running. pid %d, ppid %d, stack here %p",
+ myself->pid, myself->ppid, __builtin_frame_address (0));
+ child_info_fork ch;
+ stack_base (ch);
+
+ /* Restore the inheritance state as in parent
+ Don't call setuid here! The flags are already set. */
+ if (myself->impersonated)
+ {
+ debug_printf ("Impersonation of child, token: %d", myself->token);
+ if (myself->token == INVALID_HANDLE_VALUE)
+ RevertToSelf (); // probably not needed
+ else if (!ImpersonateLoggedOnUser (myself->token))
+ system_printf ("Impersonate for forked child failed: %E");
+ }
- MALLOC_CHECK;
+ sync_with_parent ("after longjmp.", TRUE);
+debug_printf ("hParent %p", hParent);
+ ProtectHandle (hParent);
+// small_printf ("child 1 first_dll %p, load_dlls %d\n", first_dll, load_dlls);
- /* FIXME: something is broken when copying the stack from the parent
- to the child; we try various tricks here to make sure that the
- stack is good enough to prevent page faults, but the true cause
- is still unknown. DJ */
- volatile char dummy[4096];
- dummy[0] = dummy[4095] = 0; // Just to leave some slack in the stack
+#ifdef DEBUGGING
+ char c;
+ if (GetEnvironmentVariable ("FORKDEBUG", &c, 1))
+ try_to_debug ();
+ char buf[80];
+ /* This is useful for debugging fork problems. Use gdb to attach to
+ the pid reported here. */
+ if (GetEnvironmentVariable ("CYGWIN_FORK_SLEEP", buf, sizeof (buf)))
+ {
+ small_printf ("Sleeping %d after fork, pid %u\n", atoi (buf), GetCurrentProcessId ());
+ Sleep (atoi(buf));
+ }
+#endif
- grow_stack_slack ();
+ /* If we've played with the stack, stacksize != 0. That means that
+ fork() was invoked from other than the main thread. Make sure that
+ when the "main" thread exits it calls do_exit, like a normal process.
+ Exit with a status code of 0. */
+ if (child_proc_info->stacksize)
+ {
+ ((DWORD *)child_proc_info->stackbottom)[-17] = (DWORD)do_exit;
+ ((DWORD *)child_proc_info->stackbottom)[-15] = (DWORD)0;
+ }
- debug_printf ("entering");
- /* Calculate how much of stack to copy to child */
- stack_here = stack_dummy (0);
+ MALLOC_CHECK;
- if (ISSTATE(myself, PID_SPLIT_HEAP))
+ fdtab.fixup_after_fork (hParent);
+ signal_fixup_after_fork ();
+ exec_fixup_after_fork ();
+
+ MALLOC_CHECK;
+
+ /* If we haven't dynamically loaded any dlls, just signal
+ the parent. Otherwise, load all the dlls, tell the parent
+ that we're done, and wait for the parent to fill in the.
+ loaded dlls' data/bss. */
+ if (!load_dlls)
+ sync_with_parent ("performed fork fixup.", FALSE);
+ else
{
- system_printf ("The heap has been split, CYGWIN can't fork this process.");
- system_printf ("Increase the heap_chunk_size in the registry and try again.");
- set_errno (ENOMEM);
- syscall_printf ("-1 = fork (), split heap");
- return -1;
+ dlls.load_after_fork (hParent, first_dll);
+ sync_with_parent ("loaded dlls", TRUE);
}
- /* Remember the address of the first loaded dll and decide
- if we need to load dlls. We do this here so that this
- information will be available in the parent and, when
- the stack is copied, in the child. */
- dll *first_dll = dlls.start.next;
- int load_dlls = dlls.reload_on_fork && dlls.loaded_dlls;
+ ForceCloseHandle (hParent);
+ (void) ForceCloseHandle (child_proc_info->subproc_ready);
+ (void) ForceCloseHandle (child_proc_info->forker_finished);
- static child_info_fork ch;
- x = setjmp (ch.jmp);
+ if (recreate_mmaps_after_fork (myself->mmap_ptr))
+ api_fatal ("recreate_mmaps_after_fork_failed");
- if (x == 0)
- {
- /* This will help some of the confusion. */
- fflush (stdout);
+ /* Set thread local stuff to zero. Under Windows 95/98 this is sometimes
+ non-zero, for some reason.
+ FIXME: There is a memory leak here after a fork. */
+ for (per_thread **t = threadstuff; *t; t++)
+ if ((*t)->clear_on_fork ())
+ (*t)->set ();
- subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL);
- forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL);
- ProtectHandle (subproc_ready);
- ProtectHandle (forker_finished);
+ /* Initialize signal/process handling */
+ sigproc_init ();
+ return 0;
+}
- /* If we didn't obtain all the resources we need to fork, allow the program
- to continue, but record the fact that fork won't work. */
- if (forker_finished == NULL || subproc_ready == NULL)
- {
- system_printf ("unable to allocate fork() resources.");
- system_printf ("fork() disabled.");
- return -1;
- }
+static int __stdcall
+fork_parent (HANDLE& hParent, dll *&first_dll, bool& load_dlls, child_info_fork &ch)
+{
+ HANDLE subproc_ready, forker_finished;
+ void *stack_here = &hParent;
+ DWORD rc;
+ PROCESS_INFORMATION pi = {0, NULL, 0, 0};
+ static NO_COPY HANDLE last_fork_proc = NULL;
- subproc_init ();
+ subproc_init ();
- debug_printf ("about to call setjmp");
- /* Parent. */
#ifdef DEBUGGING
- /* The ProtectHandle call allocates memory so we need to make sure
- that enough is set aside here so that the sbrk pointer does not
- move when ProtectHandle is called after the child is started.
- Otherwise the sbrk pointers in the parent will not agree with
- the child and when user_data is (regrettably) copied over,
- the user_data->ptr field will not be accurate. */
- free (malloc (4096));
+ /* The ProtectHandle call allocates memory so we need to make sure
+ that enough is set aside here so that the sbrk pointer does not
+ move when ProtectHandle is called after the child is started.
+ Otherwise the sbrk pointers in the parent will not agree with
+ the child and when user_data is (regrettably) copied over,
+ the user_data->ptr field will not be accurate. */
+ free (malloc (4096));
#endif
- init_child_info (PROC_FORK1, &ch, 1, subproc_ready);
+ int c_flags = GetPriorityClass (hMainProc) /*|
+ CREATE_NEW_PROCESS_GROUP*/;
+ STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
+
+ /* If we don't have a console, then don't create a console for the
+ child either. */
+ HANDLE console_handle = CreateFileA ("CONOUT$", GENERIC_WRITE,
+ FILE_SHARE_WRITE, &sec_none_nih,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ syscall_printf ("CreateProcessA (%s, %s,0,0,1,%x, 0,0,%p,%p)",
+ myself->progname, myself->progname, c_flags, &si, &pi);
+ if (console_handle != INVALID_HANDLE_VALUE && console_handle != 0)
+ CloseHandle (console_handle);
+ else
+ c_flags |= DETACHED_PROCESS;
- ch.forker_finished = forker_finished;
- ch.heaptop = user_data->heaptop;
- ch.heapbase = user_data->heapbase;
- ch.heapptr = user_data->heapptr;
+ hParent = NULL;
+ if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hParent, 0, 1,
+ DUPLICATE_SAME_ACCESS))
+ {
+ system_printf ("couldn't create handle to myself for child, %E");
+ return -1;
+ }
- stack_base (ch);
+ /* Remember the address of the first loaded dll and decide
+ if we need to load dlls. We do this here so that this
+ information will be available in the parent and, when
+ the stack is copied, in the child. */
+ first_dll = dlls.start.next;
+ load_dlls = dlls.reload_on_fork && dlls.loaded_dlls;
- STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
+ /* This will help some of the confusion. */
+ fflush (stdout);
- si.cb = sizeof (STARTUPINFO);
- si.lpReserved2 = (LPBYTE)&ch;
- si.cbReserved2 = sizeof(ch);
+ subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL);
+ if (subproc_ready == NULL)
+ {
+ CloseHandle (hParent);
+ system_printf ("unable to allocate subproc_ready event, %E");
+ return -1;
+ }
+ forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL);
+ if (forker_finished == NULL)
+ {
+ CloseHandle (hParent);
+ CloseHandle (subproc_ready);
+ system_printf ("unable to allocate subproc_ready event, %E");
+ return -1;
+ }
- int c_flags = GetPriorityClass (hMainProc) /*|
- CREATE_NEW_PROCESS_GROUP*/;
+ ProtectHandle (subproc_ready);
+ ProtectHandle (forker_finished);
- /* If we don't have a console, then don't create a console for the
- child either. */
- HANDLE console_handle = CreateFileA ("CONOUT$", GENERIC_WRITE,
- FILE_SHARE_WRITE, &sec_none_nih,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
- NULL);
+ init_child_info (PROC_FORK1, &ch, 1, subproc_ready);
- syscall_printf ("CreateProcessA (%s, %s,0,0,1,%x, 0,0,%p,%p)",
- myself->progname, myself->progname, c_flags, &si, &pi);
- if (console_handle != INVALID_HANDLE_VALUE && console_handle != 0)
- CloseHandle (console_handle);
- else
- c_flags |= DETACHED_PROCESS;
+ ch.forker_finished = forker_finished;
+ ch.heaptop = user_data->heaptop;
+ ch.heapbase = user_data->heapbase;
+ ch.heapptr = user_data->heapptr;
- hParent = NULL;
- if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hParent, 0, 1,
- DUPLICATE_SAME_ACCESS))
- {
- system_printf ("couldn't create handle to myself for child, %E");
- goto cleanup;
- }
+ stack_base (ch);
- /* Remove impersonation */
- uid_t uid = geteuid();
- if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE)
- seteuid (myself->orig_uid);
-
- char sa_buf[1024];
- rc = CreateProcessA (myself->progname, /* image to run */
- myself->progname, /* what we send in arg0 */
- allow_ntsec ? sec_user (sa_buf) : &sec_none_nih,
- allow_ntsec ? sec_user (sa_buf) : &sec_none_nih,
- TRUE, /* inherit handles from parent */
- c_flags,
- NULL, /* environment filled in later */
- 0, /* use current drive/directory */
- &si,
- &pi);
+ si.cb = sizeof (STARTUPINFO);
+ si.lpReserved2 = (LPBYTE)&ch;
+ si.cbReserved2 = sizeof(ch);
- CloseHandle (hParent);
+ /* Remove impersonation */
+ uid_t uid;
+ uid = geteuid();
+ if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE)
+ seteuid (myself->orig_uid);
- if (!rc)
- {
- __seterrno ();
- syscall_printf ("-1 = fork(), CreateProcessA failed");
- ForceCloseHandle(subproc_ready);
- ForceCloseHandle(forker_finished);
- subproc_ready = forker_finished = NULL;
- /* Restore impersonation */
- if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE)
- seteuid (uid);
- return -1;
- }
+ ch.parent = hParent;
+ ch.cygheap = cygheap;
+ ch.cygheap_max = cygheap_max;
- pinfo forked (cygwin_pid (pi.dwProcessId), 1);
+ char sa_buf[1024];
+ rc = CreateProcessA (myself->progname, /* image to run */
+ myself->progname, /* what we send in arg0 */
+ allow_ntsec ? sec_user (sa_buf) : &sec_none_nih,
+ allow_ntsec ? sec_user (sa_buf) : &sec_none_nih,
+ TRUE, /* inherit handles from parent */
+ c_flags,
+ NULL, /* environment filled in later */
+ 0, /* use current drive/directory */
+ &si,
+ &pi);
- /* Initialize things that are done later in dll_crt0_1 that aren't done
- for the forkee. */
- strcpy(forked->progname, myself->progname);
+ CloseHandle (hParent);
+ if (!rc)
+ {
+ __seterrno ();
+ syscall_printf ("CreateProcessA failed, %E");
+ ForceCloseHandle(subproc_ready);
+ ForceCloseHandle(forker_finished);
/* Restore impersonation */
if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE)
seteuid (uid);
+ return -1;
+ }
- ProtectHandle (pi.hThread);
- /* Protect the handle but name it similarly to the way it will
- be called in subproc handling. */
- ProtectHandle1 (pi.hProcess, childhProc);
- if (os_being_run != winNT)
- {
- if (last_fork_proc)
- CloseHandle (last_fork_proc);
- if (!DuplicateHandle (hMainProc, pi.hProcess, hMainProc, &last_fork_proc,
- 0, FALSE, DUPLICATE_SAME_ACCESS))
- system_printf ("couldn't create last_fork_proc, %E");
- }
-
- /* Fill in fields in the child's process table entry. */
- forked->ppid = myself->pid;
- forked->hProcess = pi.hProcess;
- forked->dwProcessId = pi.dwProcessId;
- forked->uid = myself->uid;
- forked->gid = myself->gid;
- forked->pgid = myself->pgid;
- forked->sid = myself->sid;
- forked->ctty = myself->ctty;
- forked->umask = myself->umask;
- forked->copysigs(myself);
- forked->process_state |= PID_INITIALIZING |
- (myself->process_state & PID_USETTY);
- memcpy (forked->username, myself->username, MAX_USER_NAME);
- if (myself->use_psid)
- {
- memcpy (forked->psid, myself->psid, MAX_SID_LEN);
- forked->use_psid = 1;
- }
- memcpy (forked->logsrv, myself->logsrv, MAX_HOST_NAME);
- memcpy (forked->domain, myself->domain, MAX_COMPUTERNAME_LENGTH+1);
- forked->token = myself->token;
- forked->impersonated = myself->impersonated;
- forked->orig_uid = myself->orig_uid;
- forked->orig_gid = myself->orig_gid;
- forked->real_uid = myself->real_uid;
- forked->real_gid = myself->real_gid;
- strcpy (forked->root, myself->root);
- forked->rootlen = myself->rootlen;
- set_child_mmap_ptr (forked);
-
- /* Wait for subproc to initialize itself. */
- if (!sync_with_child(pi, subproc_ready, TRUE, "waiting for longjmp"))
- goto cleanup;
+ pinfo forked (cygwin_pid (pi.dwProcessId), 1);
- /* CHILD IS STOPPED */
- debug_printf ("child is alive (but stopped)");
+ /* Initialize things that are done later in dll_crt0_1 that aren't done
+ for the forkee. */
+ strcpy(forked->progname, myself->progname);
- /* Initialize, in order: data, bss, heap, stack, dll data, dll bss
- Note: variables marked as NO_COPY will not be copied
- since they are placed in a protected segment. */
+ /* Restore impersonation */
+ if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE)
+ seteuid (uid);
+ ProtectHandle (pi.hThread);
+ /* Protect the handle but name it similarly to the way it will
+ be called in subproc handling. */
+ ProtectHandle1 (pi.hProcess, childhProc);
+ if (os_being_run != winNT)
+ {
+ if (last_fork_proc)
+ CloseHandle (last_fork_proc);
+ if (!DuplicateHandle (hMainProc, pi.hProcess, hMainProc, &last_fork_proc,
+ 0, FALSE, DUPLICATE_SAME_ACCESS))
+ system_printf ("couldn't create last_fork_proc, %E");
+ }
- MALLOC_CHECK;
- rc = fork_copy (pi, "user/cygwin data",
- user_data->data_start, user_data->data_end,
- user_data->bss_start, user_data->bss_end,
- ch.heapbase, ch.heapptr,
- stack_here, ch.stackbottom,
- dll_data_start, dll_data_end,
- dll_bss_start, dll_bss_end, NULL);
+ /* Fill in fields in the child's process table entry. */
+ forked->ppid = myself->pid;
+ forked->hProcess = pi.hProcess;
+ forked->dwProcessId = pi.dwProcessId;
+ forked->uid = myself->uid;
+ forked->gid = myself->gid;
+ forked->pgid = myself->pgid;
+ forked->sid = myself->sid;
+ forked->ctty = myself->ctty;
+ forked->umask = myself->umask;
+ forked->copysigs(myself);
+ forked->process_state |= PID_INITIALIZING |
+ (myself->process_state & PID_USETTY);
+ memcpy (forked->username, myself->username, MAX_USER_NAME);
+ if (myself->use_psid)
+ {
+ memcpy (forked->psid, myself->psid, MAX_SID_LEN);
+ forked->use_psid = 1;
+ }
+ memcpy (forked->logsrv, myself->logsrv, MAX_HOST_NAME);
+ memcpy (forked->domain, myself->domain, MAX_COMPUTERNAME_LENGTH+1);
+ forked->token = myself->token;
+ forked->impersonated = myself->impersonated;
+ forked->orig_uid = myself->orig_uid;
+ forked->orig_gid = myself->orig_gid;
+ forked->real_uid = myself->real_uid;
+ forked->real_gid = myself->real_gid;
+ strcpy (forked->root, myself->root);
+ forked->rootlen = myself->rootlen;
+ set_child_mmap_ptr (forked);
+
+ /* Wait for subproc to initialize itself. */
+ if (!sync_with_child(pi, subproc_ready, TRUE, "waiting for longjmp"))
+ goto cleanup;
+
+ /* CHILD IS STOPPED */
+ debug_printf ("child is alive (but stopped)");
+
+ /* Initialize, in order: data, bss, heap, stack, dll data, dll bss
+ Note: variables marked as NO_COPY will not be copied
+ since they are placed in a protected segment. */
- MALLOC_CHECK;
- if (!rc)
- goto cleanup;
- /* Now fill data/bss of any DLLs that were linked into the program. */
- for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ())
- {
- debug_printf ("copying data/bss of a linked dll");
- if (!fork_copy (pi, "linked dll data/bss", d->p.data_start, d->p.data_end,
- d->p.bss_start, d->p.bss_end,
- NULL))
- goto cleanup;
- }
+ MALLOC_CHECK;
+ rc = fork_copy (pi, "user/cygwin data",
+ user_data->data_start, user_data->data_end,
+ user_data->bss_start, user_data->bss_end,
+ ch.heapbase, ch.heapptr,
+ stack_here, ch.stackbottom,
+ dll_data_start, dll_data_end,
+ dll_bss_start, dll_bss_end, NULL);
- forked.remember ();
+ MALLOC_CHECK;
+ if (!rc)
+ goto cleanup;
- /* Start thread, and wait for it to reload dlls. */
- if (!resume_child (pi, forker_finished) ||
- !sync_with_child (pi, subproc_ready, load_dlls, "child loading dlls"))
+ /* Now fill data/bss of any DLLs that were linked into the program. */
+ for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ())
+ {
+ debug_printf ("copying data/bss of a linked dll");
+ if (!fork_copy (pi, "linked dll data/bss", d->p.data_start, d->p.data_end,
+ d->p.bss_start, d->p.bss_end,
+ NULL))
goto cleanup;
-
- /* If DLLs were loaded in the parent, then the child has reloaded all
- of them and is now waiting to have all of the individual data and
- bss sections filled in. */
- if (load_dlls)
- {
- /* CHILD IS STOPPED */
- /* write memory of reloaded dlls */
- for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ())
- {
- debug_printf ("copying data/bss for a loaded dll");
- if (!fork_copy (pi, "loaded dll data/bss", d->p.data_start, d->p.data_end,
- d->p.bss_start, d->p.bss_end,
- NULL))
- goto cleanup;
- }
- /* Start the child up again. */
- (void) resume_child (pi, forker_finished);
- }
-
- ForceCloseHandle (subproc_ready);
- ForceCloseHandle (pi.hThread);
- ForceCloseHandle (forker_finished);
- forker_finished = NULL;
- pi.hThread = NULL;
-
- res = forked->pid;
}
- else
- {
- /**** Child *****/
-
- /* We arrive here via a longjmp from "crt0". */
- (void) stack_dummy (0); // Just to make sure
- debug_printf ("child is running %d", x);
-
- debug_printf ("pid %d, ppid %d", x, myself->ppid);
-
- /* Restore the inheritance state as in parent
- Don't call setuid here! The flags are already set. */
- if (myself->impersonated)
- {
- debug_printf ("Impersonation of child, token: %d", myself->token);
- if (myself->token == INVALID_HANDLE_VALUE)
- RevertToSelf (); // probably not needed
- else if (!ImpersonateLoggedOnUser (myself->token))
- system_printf ("Impersonate for forked child failed: %E");
- }
-
- sync_with_parent ("after longjmp.", TRUE);
- ProtectHandle (hParent);
-
-#ifdef DEBUGGING
- char c;
- if (GetEnvironmentVariable ("FORKDEBUG", &c, 1))
- try_to_debug ();
- char buf[80];
- /* This is useful for debugging fork problems. Use gdb to attach to
- the pid reported here. */
- if (GetEnvironmentVariable ("CYGWIN_FORK_SLEEP", buf, sizeof (buf)))
- {
- small_printf ("Sleeping %d after fork, pid %u\n", atoi (buf), GetCurrentProcessId ());
- Sleep (atoi(buf));
- }
-#endif
-
- /* If we've played with the stack, stacksize != 0. That means that
- fork() was invoked from other than the main thread. Make sure that
- when the "main" thread exits it calls do_exit, like a normal process.
- Exit with a status code of 0. */
- if (child_proc_info->stacksize)
- {
- ((DWORD *)child_proc_info->stackbottom)[-17] = (DWORD)do_exit;
- ((DWORD *)child_proc_info->stackbottom)[-15] = (DWORD)0;
- }
-
- MALLOC_CHECK;
- cygheap_fixup_in_child (hParent, 0);
- fdtab.fixup_after_fork (hParent);
- signal_fixup_after_fork ();
- exec_fixup_after_fork ();
+ forked.remember ();
- MALLOC_CHECK;
+ /* Start thread, and wait for it to reload dlls. */
+ if (!resume_child (pi, forker_finished) ||
+ !sync_with_child (pi, subproc_ready, load_dlls, "child loading dlls"))
+ goto cleanup;
- /* If we haven't dynamically loaded any dlls, just signal
- the parent. Otherwise, load all the dlls, tell the parent
- that we're done, and wait for the parent to fill in the.
- loaded dlls' data/bss. */
- if (!load_dlls)
- sync_with_parent ("performed fork fixup.", FALSE);
- else
+ /* If DLLs were loaded in the parent, then the child has reloaded all
+ of them and is now waiting to have all of the individual data and
+ bss sections filled in. */
+ if (load_dlls)
+ {
+ /* CHILD IS STOPPED */
+ /* write memory of reloaded dlls */
+ for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ())
{
- dlls.load_after_fork (hParent, first_dll);
- sync_with_parent ("loaded dlls", TRUE);
+ debug_printf ("copying data/bss for a loaded dll");
+ if (!fork_copy (pi, "loaded dll data/bss", d->p.data_start, d->p.data_end,
+ d->p.bss_start, d->p.bss_end,
+ NULL))
+ goto cleanup;
}
-
- ForceCloseHandle (hParent);
- (void) ForceCloseHandle (child_proc_info->subproc_ready);
- (void) ForceCloseHandle (child_proc_info->forker_finished);
-
- if (recreate_mmaps_after_fork (myself->mmap_ptr))
- api_fatal ("recreate_mmaps_after_fork_failed");
-
- res = 0;
- /* Set thread local stuff to zero. Under Windows 95/98 this is sometimes
- non-zero, for some reason.
- FIXME: There is a memory leak here after a fork. */
- for (per_thread **t = threadstuff; *t; t++)
- if ((*t)->clear_on_fork ())
- (*t)->set ();
-
- /* Initialize signal/process handling */
- sigproc_init ();
+ /* Start the child up again. */
+ (void) resume_child (pi, forker_finished);
}
+ ForceCloseHandle (subproc_ready);
+ ForceCloseHandle (pi.hThread);
+ ForceCloseHandle (forker_finished);
+ forker_finished = NULL;
+ pi.hThread = NULL;
- MALLOC_CHECK;
- syscall_printf ("%d = fork()", res);
- return res;
+ return forked->pid;
/* Common cleanup code for failure cases */
cleanup:
@@ -626,15 +566,48 @@ cleanup:
ForceCloseHandle (subproc_ready);
if (forker_finished)
ForceCloseHandle (forker_finished);
- forker_finished = subproc_ready = NULL;
return -1;
}
-static volatile void
-grow_stack_slack ()
+extern "C" int
+fork ()
{
- volatile char dummy[16384];
- dummy[0] = dummy[16383] = 0; // Just to make some slack in the stack
+ struct
+ {
+ HANDLE hParent;
+ dll *first_dll;
+ bool load_dlls;
+ } grouped;
+
+ int res;
+ int x;
+
+ MALLOC_CHECK;
+
+ // grow_stack_slack ();
+
+ debug_printf ("entering");
+
+ if (ISSTATE(myself, PID_SPLIT_HEAP))
+ {
+ system_printf ("The heap has been split, CYGWIN can't fork this process.");
+ system_printf ("Increase the heap_chunk_size in the registry and try again.");
+ set_errno (ENOMEM);
+ syscall_printf ("-1 = fork (), split heap");
+ return -1;
+ }
+
+ child_info_fork ch;
+ x = setjmp (ch.jmp);
+
+ if (x != 0)
+ res = fork_child (grouped.hParent, grouped.first_dll, grouped.load_dlls);
+ else
+ res = fork_parent (grouped.hParent, grouped.first_dll, grouped.load_dlls, ch);
+
+ MALLOC_CHECK;
+ syscall_printf ("%d = fork()", res);
+ return res;
}
#ifdef NEWVFORK
diff --git a/winsup/cygwin/heap.cc b/winsup/cygwin/heap.cc
index f31848acd..db3edb00f 100644
--- a/winsup/cygwin/heap.cc
+++ b/winsup/cygwin/heap.cc
@@ -75,6 +75,7 @@ heap_init ()
brkchunk);
}
+ debug_printf ("heap base %p, heap top %p", brkbase, brktop);
page_const--;
malloc_init ();
}
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 3b8ff7d56..5e4e2e97f 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -70,6 +70,7 @@ details. */
#include "shared_info.h"
#include "registry.h"
#include "security.h"
+#include <assert.h>
static int normalize_win32_path (const char *src, char *dst);
static void slashify (const char *src, char *dst, int trailing_slash_p);
@@ -190,6 +191,7 @@ path_conv::check (const char *src, unsigned opt,
for (;;)
{
MALLOC_CHECK;
+ assert (src);
char *p = strrchr (src, '/');
if (p)
{
@@ -2163,6 +2165,7 @@ done:
static __inline char *
has_suffix (const char *path, const suffix_info *suffixes)
{
+ assert (path);
char *ext = strrchr (path, '.');
if (ext)
for (const suffix_info *ex = suffixes; ex->name != NULL; ex++)
diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc
index 3a40af574..044d85b8e 100644
--- a/winsup/cygwin/security.cc
+++ b/winsup/cygwin/security.cc
@@ -106,7 +106,7 @@ convert_string_sid_to_sid (PSID psid, const char *sid_str)
BOOL
get_pw_sid (PSID sid, struct passwd *pw)
{
- char *sp = strrchr (pw->pw_gecos, ',');
+ char *sp = pw->pw_gecos ? strrchr (pw->pw_gecos, ',') : NULL;
if (!sp)
return FALSE;
diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
index f4929f109..a2b01ccde 100644
--- a/winsup/cygwin/sigproc.cc
+++ b/winsup/cygwin/sigproc.cc
@@ -305,7 +305,6 @@ proc_subproc (DWORD what, DWORD val)
pchildren[nchildren] = vchild;
hchildren[nchildren] = vchild->hProcess;
ProtectHandle1 (vchild->hProcess, childhProc);
- nchildren++;
if (!DuplicateHandle (hMainProc, vchild->hProcess, hMainProc, &vchild->pid_handle,
0, 0, DUPLICATE_SAME_ACCESS))
system_printf ("Couldn't duplicate child handle for pid %d, %E", vchild->pid);
@@ -313,6 +312,7 @@ proc_subproc (DWORD what, DWORD val)
sigproc_printf ("added pid %d to wait list, slot %d, winpid %p, handle %p",
vchild->pid, nchildren, vchild->dwProcessId,
vchild->hProcess);
+ nchildren++;
wake_wait_subproc ();
break;
@@ -1163,7 +1163,7 @@ wait_sig (VOID *)
sigcatch_main = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL);
sigcomplete_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL);
sigcomplete_main = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
- sigproc_printf ("sigcatch_nonmain %p", sigcatch_nonmain);
+ sigproc_printf ("sigcatch_nonmain %p, sigcatch_main %p", sigcatch_nonmain, sigcatch_main);
/* Setting dwProcessId flags that this process is now capable of receiving
* signals. Prior to this, dwProcessId was set to the windows pid of
diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc
index 92494a472..badf0001a 100644
--- a/winsup/cygwin/strace.cc
+++ b/winsup/cygwin/strace.cc
@@ -21,7 +21,7 @@ details. */
#define PROTECT(x) x[sizeof(x)-1] = 0
#define CHECK(x) if (x[sizeof(x)-1] != 0) { small_printf("array bound exceeded %d\n", __LINE__); ExitProcess(1); }
-class strace NO_COPY strace;
+class NO_COPY strace strace;
/* 'twould be nice to declare this in winsup.h but winsup.h doesn't require
stdarg.h, so we declare it here instead. */
@@ -31,9 +31,9 @@ class strace NO_COPY strace;
int
strace::microseconds()
{
- static int first_microsec = 0;
- static long long hires_frequency = 0;
- static int hires_initted = 0;
+ static NO_COPY int first_microsec = 0;
+ static NO_COPY long long hires_frequency = 0;
+ static NO_COPY int hires_initted = 0;
int microsec;
@@ -104,7 +104,7 @@ strace::vsprntf (char *buf, const char *func, const char *infmt, va_list ap)
{
int count;
char fmt[80];
- static int nonewline = FALSE;
+ static NO_COPY int nonewline = FALSE;
DWORD err = GetLastError ();
const char *tn = threadname (0);
char *pn = __progname ?: myself->progname;
@@ -121,7 +121,9 @@ strace::vsprntf (char *buf, const char *func, const char *infmt, va_list ap)
else
{
char *p, progname[MAX_PATH + 1];
- if ((p = strrchr (pn, '\\')) != NULL)
+ if (!pn)
+ p = (char *) "*** unknown ***";
+ else if ((p = strrchr (pn, '\\')) != NULL)
p++;
else if ((p = strrchr (pn, '/')) != NULL)
p++;
@@ -206,7 +208,7 @@ strace::prntf (unsigned category, const char *func, const char *fmt, ...)
SetLastError (err);
}
-static const struct tab
+static NO_COPY const struct tab
{
int v;
const char *n;