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,114 +173,184 @@ 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"); + } + + 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; - /* 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 + fdtab.fixup_after_fork (hParent); + signal_fixup_after_fork (); + exec_fixup_after_fork (); - grow_stack_slack (); + MALLOC_CHECK; - debug_printf ("entering"); - /* Calculate how much of stack to copy to child */ - stack_here = stack_dummy (0); - - if (ISSTATE(myself, PID_SPLIT_HEAP)) + /* 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"); + 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"); + + /* 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; } @@ -288,332 +358,202 @@ fork () 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; + first_dll = dlls.start.next; + load_dlls = dlls.reload_on_fork && dlls.loaded_dlls; - static child_info_fork ch; - x = setjmp (ch.jmp); + /* This will help some of the confusion. */ + 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); + 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) - { - __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; - } + ProtectHandle (subproc_ready); + ProtectHandle (forker_finished); - 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 - for the forkee. */ - strcpy(forked->progname, myself->progname); + ch.forker_finished = forker_finished; + ch.heaptop = user_data->heaptop; + 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 */ 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"); - } + pinfo forked (cygwin_pid (pi.dwProcessId), 1); - /* 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); + /* Initialize things that are done later in dll_crt0_1 that aren't done + for the forkee. */ + strcpy(forked->progname, myself->progname); - /* Wait for subproc to initialize itself. */ - if (!sync_with_child(pi, subproc_ready, TRUE, "waiting for longjmp")) + /* 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"); + } + + /* 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; + } + 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 */ - 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 ()) + /* write memory of reloaded dlls */ + for (dll *d = dlls.istart (DLL_LOAD); 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, + 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; } - - 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 */ - /* 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 (); + /* 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;