Cygwin: make sure exec'ed process exists early in process list

killpg(pgid, 0) (or kill_pgrp(pgid, si_signo=0), in signal.cc)
fails (returns -1) even when there is a process in the process
group pgid, if the process is in the middle of spawnve(), see

  https://cygwin.com/pipermail/cygwin/2022-May/251479.html

When exec'ing a process the assumption is that the exec'ed process creates its
own symlink (in pinfo::thisproc() in pinfo.cc). If the exec'ing process
calls NtClose on it's own winpid symlink, but the exec'ed process didn't
progress enough into initialization, there's a slim chance that neither
the exec'ing process, nor the exec'ed process has a winpid symlink
attached.

Always create the winpid symlink in spawn.cc, even for exec'ed Cygwin
processes.  Make sure to dup the handle into the new process, and stop
creating the winpid symlink in exec'ed processes.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2022-05-19 10:46:33 +02:00
parent 1559f7f458
commit 1b86dd7d8c
3 changed files with 16 additions and 9 deletions

View File

@ -55,10 +55,11 @@ void
pinfo::thisproc (HANDLE h) pinfo::thisproc (HANDLE h)
{ {
procinfo = NULL; procinfo = NULL;
bool execed = !!h;
DWORD flags = PID_IN_USE | PID_ACTIVE; DWORD flags = PID_IN_USE | PID_ACTIVE;
/* Forked process or process started from non-Cygwin parent needs a pid. */ /* Forked process or process started from non-Cygwin parent needs a pid. */
if (!h) if (!execed)
{ {
cygheap->pid = create_cygwin_pid (); cygheap->pid = create_cygwin_pid ();
flags |= PID_NEW; flags |= PID_NEW;
@ -72,7 +73,8 @@ pinfo::thisproc (HANDLE h)
procinfo->dwProcessId = myself_initial.dwProcessId; procinfo->dwProcessId = myself_initial.dwProcessId;
procinfo->sendsig = myself_initial.sendsig; procinfo->sendsig = myself_initial.sendsig;
wcscpy (procinfo->progname, myself_initial.progname); wcscpy (procinfo->progname, myself_initial.progname);
create_winpid_symlink (); if (!execed)
create_winpid_symlink ();
procinfo->exec_sendsig = NULL; procinfo->exec_sendsig = NULL;
procinfo->exec_dwProcessId = 0; procinfo->exec_dwProcessId = 0;
debug_printf ("myself dwProcessId %u", procinfo->dwProcessId); debug_printf ("myself dwProcessId %u", procinfo->dwProcessId);

View File

@ -3,3 +3,7 @@ Bug Fixes
- Fix an issue that command "cmd /c script -c cmd" crashes if it - Fix an issue that command "cmd /c script -c cmd" crashes if it
is issued in console of Windows 7. is issued in console of Windows 7.
- Fix killpg failing because the exec'ing as well as the exec'ed
process are not in the pidlist for a brief moment.
Addresses: https://cygwin.com/pipermail/cygwin/2022-May/251479.html

View File

@ -860,13 +860,14 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
strace.execing = 1; strace.execing = 1;
myself.hProcess = hExeced = pi.hProcess; myself.hProcess = hExeced = pi.hProcess;
HANDLE old_winpid_hdl = myself.shared_winpid_handle (); HANDLE old_winpid_hdl = myself.shared_winpid_handle ();
if (!real_path.iscygexec ()) /* We have to create a new winpid symlink on behalf of the child
{ process. For Cygwin processes we also have to create a reference
/* If the child process is not a Cygwin process, we have to in the child. */
create a new winpid symlink on behalf of the child process myself.create_winpid_symlink ();
not being able to do this by itself. */ if (real_path.iscygexec ())
myself.create_winpid_symlink (); DuplicateHandle (GetCurrentProcess (),
} myself.shared_winpid_handle (),
pi.hProcess, NULL, 0, 0, DUPLICATE_SAME_ACCESS);
NtClose (old_winpid_hdl); NtClose (old_winpid_hdl);
real_path.get_wide_win32_path (myself->progname); // FIXME: race? real_path.get_wide_win32_path (myself->progname); // FIXME: race?
sigproc_printf ("new process name %W", myself->progname); sigproc_printf ("new process name %W", myself->progname);