Cygwin: pty: Avoid cutting the branch the pty master is sitting on.

- When Ctrl-C terminates a non-cygwin process on a pseudo console,
  pty master attaches to the pseudo console first, and send
  CTRL_C_EVENT. If the non-cygwin process closes the pseudo console
  before the pty master calls FreeConsole(), the pty master process
  will crash. With this patch, pty master process takes over the
  ownership of the pseudo console, and closes it by myself.
This commit is contained in:
Takashi Yano 2022-03-01 11:34:16 +09:00
parent 644e8bba07
commit fbfea31dd9
5 changed files with 65 additions and 50 deletions

View File

@ -1157,6 +1157,9 @@ ctrl_c_handler (DWORD type)
tty_min *t = cygwin_shared->tty.get_cttyp (); tty_min *t = cygwin_shared->tty.get_cttyp ();
if (!t)
return TRUE;
/* If process group leader is non-cygwin process or not exist, /* If process group leader is non-cygwin process or not exist,
send signal to myself. */ send signal to myself. */
pinfo pi (t->getpgid ()); pinfo pi (t->getpgid ());

View File

@ -2409,6 +2409,8 @@ class fhandler_pty_slave: public fhandler_pty_common
static void cleanup_for_non_cygwin_app (handle_set_t *p, tty *ttyp, static void cleanup_for_non_cygwin_app (handle_set_t *p, tty *ttyp,
bool stdin_is_ptys); bool stdin_is_ptys);
void setpgid_aux (pid_t pid); void setpgid_aux (pid_t pid);
static void close_pseudoconsole_if_necessary (tty *ttyp,
fhandler_termios *fh);
}; };
#define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit)) #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))

View File

@ -357,6 +357,7 @@ fhandler_termios::process_sigs (char c, tty* ttyp, fhandler_termios *fh)
which the target process is attaching before sending the which the target process is attaching before sending the
CTRL_C_EVENT. After sending the event, reattach to the CTRL_C_EVENT. After sending the event, reattach to the
console to which the process was previously attached. */ console to which the process was previously attached. */
bool console_exists = fhandler_console::exists ();
pinfo pinfo_resume = pinfo (myself->ppid); pinfo pinfo_resume = pinfo (myself->ppid);
DWORD resume_pid = 0; DWORD resume_pid = 0;
if (pinfo_resume) if (pinfo_resume)
@ -364,11 +365,12 @@ fhandler_termios::process_sigs (char c, tty* ttyp, fhandler_termios *fh)
else else
resume_pid = fhandler_pty_common::get_console_process_id resume_pid = fhandler_pty_common::get_console_process_id
(myself->dwProcessId, false); (myself->dwProcessId, false);
if (resume_pid && fh && !fh->is_console ()) if ((!console_exists || resume_pid) && fh && !fh->is_console ())
{ {
FreeConsole (); FreeConsole ();
AttachConsole (p->dwProcessId); AttachConsole (p->dwProcessId);
init_console_handler (true); init_console_handler (::cygheap->ctty
&& ::cygheap->ctty->is_console ());
} }
if (fh && p == myself && being_debugged ()) if (fh && p == myself && being_debugged ())
{ /* Avoid deadlock in gdb on console. */ { /* Avoid deadlock in gdb on console. */
@ -388,11 +390,19 @@ fhandler_termios::process_sigs (char c, tty* ttyp, fhandler_termios *fh)
GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0); GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0);
ctrl_c_event_sent = true; ctrl_c_event_sent = true;
} }
if (resume_pid && fh && !fh->is_console ()) if ((!console_exists || resume_pid) && fh && !fh->is_console ())
{ {
/* If a process on pseudo console is killed by Ctrl-C,
this process may take over the ownership of the
pseudo console because this process attached to it
before sending CTRL_C_EVENT. In this case, closing
pseudo console is necessary. */
fhandler_pty_slave::close_pseudoconsole_if_necessary (ttyp, fh);
FreeConsole (); FreeConsole ();
AttachConsole (resume_pid); if (resume_pid && console_exists)
init_console_handler (true); AttachConsole (resume_pid);
init_console_handler (::cygheap->ctty
&& ::cygheap->ctty->is_console ());
} }
need_discard_input = true; need_discard_input = true;
} }

View File

@ -537,7 +537,8 @@ fhandler_pty_master::accept_input ()
resume_pid = pinfo_resume->dwProcessId; resume_pid = pinfo_resume->dwProcessId;
else else
resume_pid = get_console_process_id (myself->dwProcessId, false); resume_pid = get_console_process_id (myself->dwProcessId, false);
if (target_pid && resume_pid) bool console_exists = fhandler_console::exists ();
if (target_pid && (resume_pid || !console_exists))
{ {
/* Slave attaches to a different console than master. /* Slave attaches to a different console than master.
Therefore reattach here. */ Therefore reattach here. */
@ -546,8 +547,9 @@ fhandler_pty_master::accept_input ()
AttachConsole (target_pid); AttachConsole (target_pid);
cp_to = GetConsoleCP (); cp_to = GetConsoleCP ();
FreeConsole (); FreeConsole ();
AttachConsole (resume_pid); if (resume_pid && console_exists)
init_console_handler (true); AttachConsole (resume_pid);
init_console_handler (false);
release_attach_mutex (); release_attach_mutex ();
} }
else else
@ -1029,12 +1031,12 @@ fhandler_pty_slave::close ()
if (!ForceCloseHandle (get_handle_nat ())) if (!ForceCloseHandle (get_handle_nat ()))
termios_printf ("CloseHandle (get_handle_nat ()<%p>), %E", termios_printf ("CloseHandle (get_handle_nat ()<%p>), %E",
get_handle_nat ()); get_handle_nat ());
if ((unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
fhandler_console::free_console (); /* assumes that we are the last pty closer */
fhandler_pty_common::close (); fhandler_pty_common::close ();
if (!ForceCloseHandle (output_mutex)) if (!ForceCloseHandle (output_mutex))
termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex); termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex);
get_ttyp ()->invisible_console_pid = 0; if (get_ttyp ()->invisible_console_pid
&& !pinfo (get_ttyp ()->invisible_console_pid))
get_ttyp ()->invisible_console_pid = 0;
return 0; return 0;
} }
@ -1122,7 +1124,7 @@ pcon_pid_alive (DWORD pid)
inline static bool inline static bool
pcon_pid_self (DWORD pid) pcon_pid_self (DWORD pid)
{ {
return (pid == myself->exec_dwProcessId); return (pid == (myself->exec_dwProcessId ?: myself->dwProcessId));
} }
void void
@ -1240,14 +1242,14 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
0, TRUE, DUPLICATE_SAME_ACCESS); 0, TRUE, DUPLICATE_SAME_ACCESS);
FreeConsole (); FreeConsole ();
AttachConsole (get_ttyp ()->pcon_pid); AttachConsole (get_ttyp ()->pcon_pid);
init_console_handler (true); init_console_handler (false);
WaitForSingleObject (input_mutex, mutex_timeout); WaitForSingleObject (input_mutex, mutex_timeout);
transfer_input (tty::to_cyg, h_pcon_in, get_ttyp (), transfer_input (tty::to_cyg, h_pcon_in, get_ttyp (),
input_available_event); input_available_event);
ReleaseMutex (input_mutex); ReleaseMutex (input_mutex);
FreeConsole (); FreeConsole ();
AttachConsole (resume_pid); AttachConsole (resume_pid);
init_console_handler (true); init_console_handler (false);
CloseHandle (h_pcon_in); CloseHandle (h_pcon_in);
} }
CloseHandle (pcon_owner); CloseHandle (pcon_owner);
@ -2839,7 +2841,8 @@ fhandler_pty_master::pty_master_fwd_thread (const master_fwd_thread_param_t *p)
resume_pid = pinfo_resume->dwProcessId; resume_pid = pinfo_resume->dwProcessId;
else else
resume_pid = get_console_process_id (myself->dwProcessId, false); resume_pid = get_console_process_id (myself->dwProcessId, false);
if (target_pid && resume_pid) bool console_exists = fhandler_console::exists ();
if (target_pid && (resume_pid || !console_exists))
{ {
/* Slave attaches to a different console than master. /* Slave attaches to a different console than master.
Therefore reattach here. */ Therefore reattach here. */
@ -2848,8 +2851,9 @@ fhandler_pty_master::pty_master_fwd_thread (const master_fwd_thread_param_t *p)
AttachConsole (target_pid); AttachConsole (target_pid);
cp_from = GetConsoleOutputCP (); cp_from = GetConsoleOutputCP ();
FreeConsole (); FreeConsole ();
AttachConsole (resume_pid); if (resume_pid && console_exists)
init_console_handler (true); AttachConsole (resume_pid);
init_console_handler (false);
release_attach_mutex (); release_attach_mutex ();
} }
else else
@ -3272,7 +3276,7 @@ fhandler_pty_slave::setup_pseudoconsole (bool nopcon)
CloseHandle (pcon_owner); CloseHandle (pcon_owner);
FreeConsole (); FreeConsole ();
AttachConsole (get_ttyp ()->pcon_pid); AttachConsole (get_ttyp ()->pcon_pid);
init_console_handler (true); init_console_handler (false);
goto skip_create; goto skip_create;
} }
@ -3396,7 +3400,7 @@ fhandler_pty_slave::setup_pseudoconsole (bool nopcon)
/* Attach to pseudo console */ /* Attach to pseudo console */
FreeConsole (); FreeConsole ();
AttachConsole (pi.dwProcessId); AttachConsole (pi.dwProcessId);
init_console_handler (true); init_console_handler (false);
/* Terminate helper process */ /* Terminate helper process */
SetEvent (goodbye); SetEvent (goodbye);
@ -3531,6 +3535,8 @@ fhandler_pty_slave::close_pseudoconsole (tty *ttyp, DWORD force_switch_to)
/* Search another process which attaches to the pseudo console */ /* Search another process which attaches to the pseudo console */
DWORD current_pid = myself->exec_dwProcessId ?: myself->dwProcessId; DWORD current_pid = myself->exec_dwProcessId ?: myself->dwProcessId;
switch_to = get_console_process_id (current_pid, false, true, true); switch_to = get_console_process_id (current_pid, false, true, true);
if (!switch_to)
switch_to = get_console_process_id (current_pid, false, true, false);
} }
if (ttyp->pcon_activated) if (ttyp->pcon_activated)
{ {
@ -3579,27 +3585,17 @@ fhandler_pty_slave::close_pseudoconsole (tty *ttyp, DWORD force_switch_to)
ttyp->h_pcon_out = new_pcon_out; ttyp->h_pcon_out = new_pcon_out;
FreeConsole (); FreeConsole ();
pinfo p (myself->ppid); pinfo p (myself->ppid);
if (p) if (!p || !AttachConsole (p->dwProcessId))
{
if (!AttachConsole (p->dwProcessId))
AttachConsole (ATTACH_PARENT_PROCESS);
}
else
AttachConsole (ATTACH_PARENT_PROCESS); AttachConsole (ATTACH_PARENT_PROCESS);
init_console_handler (true); init_console_handler (false);
} }
else else
{ /* Close pseudo console */ { /* Close pseudo console */
FreeConsole (); FreeConsole ();
pinfo p (myself->ppid); pinfo p (myself->ppid);
if (p) if (!p || !AttachConsole (p->dwProcessId))
{
if (!AttachConsole (p->dwProcessId))
AttachConsole (ATTACH_PARENT_PROCESS);
}
else
AttachConsole (ATTACH_PARENT_PROCESS); AttachConsole (ATTACH_PARENT_PROCESS);
init_console_handler (true); init_console_handler (false);
/* Reconstruct pseudo console handler container here for close */ /* Reconstruct pseudo console handler container here for close */
HPCON_INTERNAL *hp = HPCON_INTERNAL *hp =
(HPCON_INTERNAL *) HeapAlloc (GetProcessHeap (), 0, (HPCON_INTERNAL *) HeapAlloc (GetProcessHeap (), 0,
@ -3621,14 +3617,9 @@ fhandler_pty_slave::close_pseudoconsole (tty *ttyp, DWORD force_switch_to)
{ {
FreeConsole (); FreeConsole ();
pinfo p (myself->ppid); pinfo p (myself->ppid);
if (p) if (!p || !AttachConsole (p->dwProcessId))
{
if (!AttachConsole (p->dwProcessId))
AttachConsole (ATTACH_PARENT_PROCESS);
}
else
AttachConsole (ATTACH_PARENT_PROCESS); AttachConsole (ATTACH_PARENT_PROCESS);
init_console_handler (true); init_console_handler (false);
} }
} }
else if (pcon_pid_self (ttyp->pcon_pid)) else if (pcon_pid_self (ttyp->pcon_pid))
@ -3795,7 +3786,7 @@ fhandler_pty_slave::create_invisible_console ()
/* Detach from console device and create new invisible console. */ /* Detach from console device and create new invisible console. */
FreeConsole(); FreeConsole();
fhandler_console::need_invisible (true); fhandler_console::need_invisible (true);
init_console_handler (true); init_console_handler (false);
get_ttyp ()->need_invisible_console = false; get_ttyp ()->need_invisible_console = false;
get_ttyp ()->invisible_console_pid = myself->pid; get_ttyp ()->invisible_console_pid = myself->pid;
} }
@ -4102,7 +4093,7 @@ fhandler_pty_slave::setpgid_aux (pid_t pid)
CloseHandle (pcon_owner); CloseHandle (pcon_owner);
FreeConsole (); FreeConsole ();
AttachConsole (get_ttyp ()->pcon_pid); AttachConsole (get_ttyp ()->pcon_pid);
init_console_handler (true); init_console_handler (false);
attach_restore = true; attach_restore = true;
} }
WaitForSingleObject (input_mutex, mutex_timeout); WaitForSingleObject (input_mutex, mutex_timeout);
@ -4112,14 +4103,9 @@ fhandler_pty_slave::setpgid_aux (pid_t pid)
{ {
FreeConsole (); FreeConsole ();
pinfo p (myself->ppid); pinfo p (myself->ppid);
if (p) if (!p || !AttachConsole (p->dwProcessId))
{
if (!AttachConsole (p->dwProcessId))
AttachConsole (ATTACH_PARENT_PROCESS);
}
else
AttachConsole (ATTACH_PARENT_PROCESS); AttachConsole (ATTACH_PARENT_PROCESS);
init_console_handler (true); init_console_handler (false);
} }
} }
ReleaseMutex (pcon_mutex); ReleaseMutex (pcon_mutex);
@ -4135,3 +4121,16 @@ fhandler_pty_master::need_send_ctrl_c_event ()
return !(to_be_read_from_pcon () && get_ttyp ()->pcon_activated return !(to_be_read_from_pcon () && get_ttyp ()->pcon_activated
&& get_ttyp ()->pcon_input_state == tty::to_nat); && get_ttyp ()->pcon_input_state == tty::to_nat);
} }
void
fhandler_pty_slave::close_pseudoconsole_if_necessary (tty *ttyp,
fhandler_termios *fh)
{
if (fh->get_major () == DEV_PTYM_MAJOR && ttyp->pcon_activated)
{
fhandler_pty_master *ptym = (fhandler_pty_master *) fh;
WaitForSingleObject (ptym->pcon_mutex, INFINITE);
close_pseudoconsole (ttyp);
ReleaseMutex (ptym->pcon_mutex);
}
}

View File

@ -1392,7 +1392,8 @@ wait_sig (VOID *)
sig_held = true; sig_held = true;
break; break;
case __SIGSETPGRP: case __SIGSETPGRP:
init_console_handler (true); init_console_handler (::cygheap->ctty
&& ::cygheap->ctty->is_console ());
break; break;
case __SIGTHREADEXIT: case __SIGTHREADEXIT:
{ {