From 1ec4f618feb517c020ff25784bedc66dd4f6f0e2 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Thu, 12 Oct 2000 22:15:47 +0000 Subject: * 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. --- winsup/cygwin/ChangeLog | 23 ++ winsup/cygwin/child_info.h | 11 +- winsup/cygwin/cygheap.cc | 4 +- winsup/cygwin/dcrt0.cc | 5 +- winsup/cygwin/debug.cc | 4 + winsup/cygwin/dtable.cc | 4 +- winsup/cygwin/exceptions.cc | 2 +- winsup/cygwin/fork.cc | 727 +++++++++++++++++++++----------------------- winsup/cygwin/heap.cc | 1 + winsup/cygwin/path.cc | 3 + winsup/cygwin/security.cc | 2 +- winsup/cygwin/sigproc.cc | 4 +- winsup/cygwin/strace.cc | 16 +- 13 files changed, 407 insertions(+), 399 deletions(-) (limited to 'winsup/cygwin') 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 + + * 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 * 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 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; -- cgit v1.2.3