* 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.
This commit is contained in:
Christopher Faylor 2000-10-12 22:15:47 +00:00
parent 5e0d760fb8
commit 1ec4f618fe
13 changed files with 422 additions and 414 deletions

View File

@ -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> Thu Oct 12 00:25:29 2000 Christopher Faylor <cgf@cygnus.com>
* errno.cc (seterrno_from_win_error): Fix debugging output. * errno.cc (seterrno_from_win_error): Fix debugging output.

View File

@ -12,7 +12,7 @@ details. */
enum enum
{ {
PROC_MAGIC = 0xaf08f000, PROC_MAGIC = 0xaf09f000,
PROC_FORK = PROC_MAGIC + 1, PROC_FORK = PROC_MAGIC + 1,
PROC_EXEC = PROC_MAGIC + 2, PROC_EXEC = PROC_MAGIC + 2,
PROC_SPAWN = PROC_MAGIC + 3, PROC_SPAWN = PROC_MAGIC + 3,
@ -37,6 +37,9 @@ public:
HANDLE shared_h; HANDLE shared_h;
HANDLE console_h; HANDLE console_h;
HANDLE parent_alive; // handle of thread used to track children HANDLE parent_alive; // handle of thread used to track children
HANDLE parent;
void *cygheap;
void *cygheap_max;
}; };
class child_info_fork: public child_info class child_info_fork: public child_info
@ -72,13 +75,9 @@ public:
class child_info_spawn: public child_info class child_info_spawn: public child_info
{ {
public: public:
HANDLE parent;
void *cygheap;
void *cygheap_max;
cygheap_exec_info *moreinfo; cygheap_exec_info *moreinfo;
child_info_spawn (): parent (NULL), cygheap (NULL), child_info_spawn (): moreinfo (NULL) {}
cygheap_max (NULL), moreinfo (NULL) {}
~child_info_spawn () ~child_info_spawn ()
{ {
if (parent) if (parent)

View File

@ -18,8 +18,8 @@
#include "cygerrno.h" #include "cygerrno.h"
#include "sync.h" #include "sync.h"
void *cygheap = NULL; void NO_COPY *cygheap = NULL;
void *cygheap_max = NULL; void NO_COPY *cygheap_max = NULL;
static NO_COPY muto *cygheap_protect = NULL; static NO_COPY muto *cygheap_protect = NULL;

View File

@ -662,10 +662,13 @@ dll_crt0_1 ()
if (child_proc_info) if (child_proc_info)
{ {
cygheap = child_proc_info->cygheap;
cygheap_max = child_proc_info->cygheap_max;
switch (child_proc_info->type) switch (child_proc_info->type)
{ {
case PROC_FORK: case PROC_FORK:
case PROC_FORK1: case PROC_FORK1:
cygheap_fixup_in_child (child_proc_info->parent, 0);
alloc_stack (fork_info); alloc_stack (fork_info);
set_myself (mypid); set_myself (mypid);
user_data->forkee = child_proc_info->cygpid; user_data->forkee = child_proc_info->cygpid;
@ -677,8 +680,6 @@ dll_crt0_1 ()
case PROC_EXEC: case PROC_EXEC:
case PROC_SPAWN: case PROC_SPAWN:
HANDLE h; HANDLE h;
cygheap = spawn_info->cygheap;
cygheap_max = spawn_info->cygheap_max;
cygheap_fixup_in_child (spawn_info->parent, 1); cygheap_fixup_in_child (spawn_info->parent, 1);
if (!spawn_info->moreinfo->myself_pinfo || if (!spawn_info->moreinfo->myself_pinfo ||
!DuplicateHandle (hMainProc, spawn_info->moreinfo->myself_pinfo, !DuplicateHandle (hMainProc, spawn_info->moreinfo->myself_pinfo,

View File

@ -306,6 +306,10 @@ close_handle (const char *func, int ln, HANDLE h, const char *name, BOOL force)
} }
unlock_debug (); 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; return ret;
} }
#endif /*DEBUGGING*/ #endif /*DEBUGGING*/

View File

@ -472,7 +472,9 @@ dtable::fixup_after_fork (HANDLE parent)
for (size_t i = 0; i < size; i++) for (size_t i = 0; i < size; i++)
if ((fh = fds[i]) != NULL) 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 ()); debug_printf ("fd %d(%s)", i, fh->get_name ());
fh->fixup_after_fork (parent); fh->fixup_after_fork (parent);

View File

@ -385,7 +385,7 @@ try_to_debug ()
static void static void
stackdump (EXCEPTION_RECORD *e, CONTEXT *in) stackdump (EXCEPTION_RECORD *e, CONTEXT *in)
{ {
char *p; const char *p;
if (myself->progname[0]) if (myself->progname[0])
{ {
/* write to progname.stackdump if possible */ /* write to progname.stackdump if possible */

View File

@ -173,114 +173,184 @@ sync_with_child (PROCESS_INFORMATION &pi, HANDLE subproc_ready,
} }
debug_printf ("child signalled me"); debug_printf ("child signalled me");
if (hang_child)
{
int n = SuspendThread (pi.hThread);
debug_printf ("suspend count %d", n); \
}
return 1; return 1;
} }
static int static int
resume_child (PROCESS_INFORMATION &pi, HANDLE forker_finished) resume_child (PROCESS_INFORMATION &pi, HANDLE forker_finished)
{ {
int rc;
debug_printf ("here");
SetEvent (forker_finished); SetEvent (forker_finished);
debug_printf ("signalled child");
rc = ResumeThread (pi.hThread); return 1;
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;
} }
/* Notify parent that it is time for the next step. /* 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 Note that this has to be a macro since the parent may be messing with
our stack. */ our stack. */
#define sync_with_parent(s, hang_self) \ static void __stdcall
((void) ({ \ sync_with_parent(const char *s, bool hang_self)
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)
{ {
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 static int __stdcall
fork () fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls)
{ {
int res; debug_printf ("child is running. pid %d, ppid %d, stack here %p",
DWORD rc; myself->pid, myself->ppid, __builtin_frame_address (0));
HANDLE hParent; child_info_fork ch;
HANDLE subproc_ready, forker_finished; stack_base (ch);
void *stack_here;
int x; /* Restore the inheritance state as in parent
PROCESS_INFORMATION pi = {0, NULL, 0, 0}; Don't call setuid here! The flags are already set. */
static NO_COPY HANDLE last_fork_proc = NULL; 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);
debug_printf ("hParent %p", hParent);
ProtectHandle (hParent);
// small_printf ("child 1 first_dll %p, load_dlls %d\n", first_dll, load_dlls);
#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; MALLOC_CHECK;
/* FIXME: something is broken when copying the stack from the parent fdtab.fixup_after_fork (hParent);
to the child; we try various tricks here to make sure that the signal_fixup_after_fork ();
stack is good enough to prevent page faults, but the true cause exec_fixup_after_fork ();
is still unknown. DJ */
volatile char dummy[4096];
dummy[0] = dummy[4095] = 0; // Just to leave some slack in the stack
grow_stack_slack (); MALLOC_CHECK;
debug_printf ("entering"); /* If we haven't dynamically loaded any dlls, just signal
/* Calculate how much of stack to copy to child */ the parent. Otherwise, load all the dlls, tell the parent
stack_here = stack_dummy (0); that we're done, and wait for the parent to fill in the.
loaded dlls' data/bss. */
if (ISSTATE(myself, PID_SPLIT_HEAP)) if (!load_dlls)
sync_with_parent ("performed fork fixup.", FALSE);
else
{ {
system_printf ("The heap has been split, CYGWIN can't fork this process."); dlls.load_after_fork (hParent, first_dll);
system_printf ("Increase the heap_chunk_size in the registry and try again."); sync_with_parent ("loaded dlls", TRUE);
set_errno (ENOMEM); }
syscall_printf ("-1 = fork (), split heap");
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");
/* 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 ();
return 0;
}
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 ();
#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));
#endif
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;
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; return -1;
} }
@ -288,332 +358,202 @@ fork ()
if we need to load dlls. We do this here so that this if we need to load dlls. We do this here so that this
information will be available in the parent and, when information will be available in the parent and, when
the stack is copied, in the child. */ the stack is copied, in the child. */
dll *first_dll = dlls.start.next; first_dll = dlls.start.next;
int load_dlls = dlls.reload_on_fork && dlls.loaded_dlls; load_dlls = dlls.reload_on_fork && dlls.loaded_dlls;
static child_info_fork ch; /* This will help some of the confusion. */
x = setjmp (ch.jmp); fflush (stdout);
if (x == 0) subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL);
if (subproc_ready == NULL)
{ {
/* This will help some of the confusion. */
fflush (stdout);
subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL);
forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL);
ProtectHandle (subproc_ready);
ProtectHandle (forker_finished);
/* 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;
}
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));
#endif
init_child_info (PROC_FORK1, &ch, 1, subproc_ready);
ch.forker_finished = forker_finished;
ch.heaptop = user_data->heaptop;
ch.heapbase = user_data->heapbase;
ch.heapptr = user_data->heapptr;
stack_base (ch);
STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
si.cb = sizeof (STARTUPINFO);
si.lpReserved2 = (LPBYTE)&ch;
si.cbReserved2 = sizeof(ch);
int c_flags = GetPriorityClass (hMainProc) /*|
CREATE_NEW_PROCESS_GROUP*/;
/* 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;
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;
}
/* 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);
CloseHandle (hParent); 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;
}
if (!rc) ProtectHandle (subproc_ready);
{ ProtectHandle (forker_finished);
__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;
}
pinfo forked (cygwin_pid (pi.dwProcessId), 1); init_child_info (PROC_FORK1, &ch, 1, subproc_ready);
/* Initialize things that are done later in dll_crt0_1 that aren't done ch.forker_finished = forker_finished;
for the forkee. */ ch.heaptop = user_data->heaptop;
strcpy(forked->progname, myself->progname); ch.heapbase = user_data->heapbase;
ch.heapptr = user_data->heapptr;
stack_base (ch);
si.cb = sizeof (STARTUPINFO);
si.lpReserved2 = (LPBYTE)&ch;
si.cbReserved2 = sizeof(ch);
/* Remove impersonation */
uid_t uid;
uid = geteuid();
if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE)
seteuid (myself->orig_uid);
ch.parent = hParent;
ch.cygheap = cygheap;
ch.cygheap_max = cygheap_max;
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);
CloseHandle (hParent);
if (!rc)
{
__seterrno ();
syscall_printf ("CreateProcessA failed, %E");
ForceCloseHandle(subproc_ready);
ForceCloseHandle(forker_finished);
/* Restore impersonation */ /* Restore impersonation */
if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE) if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE)
seteuid (uid); seteuid (uid);
return -1;
}
ProtectHandle (pi.hThread); pinfo forked (cygwin_pid (pi.dwProcessId), 1);
/* 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. */ /* Initialize things that are done later in dll_crt0_1 that aren't done
forked->ppid = myself->pid; for the forkee. */
forked->hProcess = pi.hProcess; strcpy(forked->progname, myself->progname);
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. */ /* Restore impersonation */
if (!sync_with_child(pi, subproc_ready, TRUE, "waiting for longjmp")) 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");
}
/* 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;
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);
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; goto cleanup;
}
forked.remember ();
/* 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 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 */ /* CHILD IS STOPPED */
debug_printf ("child is alive (but stopped)"); /* write memory of reloaded dlls */
for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ())
/* 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;
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);
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"); debug_printf ("copying data/bss for a loaded dll");
if (!fork_copy (pi, "linked dll data/bss", d->p.data_start, d->p.data_end, if (!fork_copy (pi, "loaded dll data/bss", d->p.data_start, d->p.data_end,
d->p.bss_start, d->p.bss_end, d->p.bss_start, d->p.bss_end,
NULL)) NULL))
goto cleanup; goto cleanup;
} }
/* Start the child up again. */
forked.remember (); (void) resume_child (pi, forker_finished);
/* 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 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 ();
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
{
dlls.load_after_fork (hParent, first_dll);
sync_with_parent ("loaded dlls", TRUE);
}
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 ();
} }
ForceCloseHandle (subproc_ready);
ForceCloseHandle (pi.hThread);
ForceCloseHandle (forker_finished);
forker_finished = NULL;
pi.hThread = NULL;
MALLOC_CHECK; return forked->pid;
syscall_printf ("%d = fork()", res);
return res;
/* Common cleanup code for failure cases */ /* Common cleanup code for failure cases */
cleanup: cleanup:
@ -626,15 +566,48 @@ cleanup:
ForceCloseHandle (subproc_ready); ForceCloseHandle (subproc_ready);
if (forker_finished) if (forker_finished)
ForceCloseHandle (forker_finished); ForceCloseHandle (forker_finished);
forker_finished = subproc_ready = NULL;
return -1; return -1;
} }
static volatile void extern "C" int
grow_stack_slack () fork ()
{ {
volatile char dummy[16384]; struct
dummy[0] = dummy[16383] = 0; // Just to make some slack in the stack {
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 #ifdef NEWVFORK

View File

@ -75,6 +75,7 @@ heap_init ()
brkchunk); brkchunk);
} }
debug_printf ("heap base %p, heap top %p", brkbase, brktop);
page_const--; page_const--;
malloc_init (); malloc_init ();
} }

View File

@ -70,6 +70,7 @@ details. */
#include "shared_info.h" #include "shared_info.h"
#include "registry.h" #include "registry.h"
#include "security.h" #include "security.h"
#include <assert.h>
static int normalize_win32_path (const char *src, char *dst); static int normalize_win32_path (const char *src, char *dst);
static void slashify (const char *src, char *dst, int trailing_slash_p); 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 (;;) for (;;)
{ {
MALLOC_CHECK; MALLOC_CHECK;
assert (src);
char *p = strrchr (src, '/'); char *p = strrchr (src, '/');
if (p) if (p)
{ {
@ -2163,6 +2165,7 @@ done:
static __inline char * static __inline char *
has_suffix (const char *path, const suffix_info *suffixes) has_suffix (const char *path, const suffix_info *suffixes)
{ {
assert (path);
char *ext = strrchr (path, '.'); char *ext = strrchr (path, '.');
if (ext) if (ext)
for (const suffix_info *ex = suffixes; ex->name != NULL; ex++) for (const suffix_info *ex = suffixes; ex->name != NULL; ex++)

View File

@ -106,7 +106,7 @@ convert_string_sid_to_sid (PSID psid, const char *sid_str)
BOOL BOOL
get_pw_sid (PSID sid, struct passwd *pw) 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) if (!sp)
return FALSE; return FALSE;

View File

@ -305,7 +305,6 @@ proc_subproc (DWORD what, DWORD val)
pchildren[nchildren] = vchild; pchildren[nchildren] = vchild;
hchildren[nchildren] = vchild->hProcess; hchildren[nchildren] = vchild->hProcess;
ProtectHandle1 (vchild->hProcess, childhProc); ProtectHandle1 (vchild->hProcess, childhProc);
nchildren++;
if (!DuplicateHandle (hMainProc, vchild->hProcess, hMainProc, &vchild->pid_handle, if (!DuplicateHandle (hMainProc, vchild->hProcess, hMainProc, &vchild->pid_handle,
0, 0, DUPLICATE_SAME_ACCESS)) 0, 0, DUPLICATE_SAME_ACCESS))
system_printf ("Couldn't duplicate child handle for pid %d, %E", vchild->pid); 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", sigproc_printf ("added pid %d to wait list, slot %d, winpid %p, handle %p",
vchild->pid, nchildren, vchild->dwProcessId, vchild->pid, nchildren, vchild->dwProcessId,
vchild->hProcess); vchild->hProcess);
nchildren++;
wake_wait_subproc (); wake_wait_subproc ();
break; break;
@ -1163,7 +1163,7 @@ wait_sig (VOID *)
sigcatch_main = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL); sigcatch_main = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL);
sigcomplete_nonmain = 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); 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 /* Setting dwProcessId flags that this process is now capable of receiving
* signals. Prior to this, dwProcessId was set to the windows pid of * signals. Prior to this, dwProcessId was set to the windows pid of

View File

@ -21,7 +21,7 @@ details. */
#define PROTECT(x) x[sizeof(x)-1] = 0 #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); } #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 /* 'twould be nice to declare this in winsup.h but winsup.h doesn't require
stdarg.h, so we declare it here instead. */ stdarg.h, so we declare it here instead. */
@ -31,9 +31,9 @@ class strace NO_COPY strace;
int int
strace::microseconds() strace::microseconds()
{ {
static int first_microsec = 0; static NO_COPY int first_microsec = 0;
static long long hires_frequency = 0; static NO_COPY long long hires_frequency = 0;
static int hires_initted = 0; static NO_COPY int hires_initted = 0;
int microsec; int microsec;
@ -104,7 +104,7 @@ strace::vsprntf (char *buf, const char *func, const char *infmt, va_list ap)
{ {
int count; int count;
char fmt[80]; char fmt[80];
static int nonewline = FALSE; static NO_COPY int nonewline = FALSE;
DWORD err = GetLastError (); DWORD err = GetLastError ();
const char *tn = threadname (0); const char *tn = threadname (0);
char *pn = __progname ?: myself->progname; char *pn = __progname ?: myself->progname;
@ -121,7 +121,9 @@ strace::vsprntf (char *buf, const char *func, const char *infmt, va_list ap)
else else
{ {
char *p, progname[MAX_PATH + 1]; char *p, progname[MAX_PATH + 1];
if ((p = strrchr (pn, '\\')) != NULL) if (!pn)
p = (char *) "*** unknown ***";
else if ((p = strrchr (pn, '\\')) != NULL)
p++; p++;
else if ((p = strrchr (pn, '/')) != NULL) else if ((p = strrchr (pn, '/')) != NULL)
p++; p++;
@ -206,7 +208,7 @@ strace::prntf (unsigned category, const char *func, const char *fmt, ...)
SetLastError (err); SetLastError (err);
} }
static const struct tab static NO_COPY const struct tab
{ {
int v; int v;
const char *n; const char *n;