[newlib-cygwin] Cygwin: pty: Restore nat handles in all PTY-slave instances in GDB
Takashi Yano
tyan0@sourceware.org
Mon Apr 6 12:18:48 GMT 2026
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=c8f08427661b1f054e2fed93b4c1ce5ad00d882e
commit c8f08427661b1f054e2fed93b4c1ce5ad00d882e
Author: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Sun Mar 8 20:00:44 2026 +0900
Cygwin: pty: Restore nat handles in all PTY-slave instances in GDB
If non-cygwin app is started in GDB and terminating it normally,
re-running the non-cygwin app might fail in setup_pseudoconsole().
The error is something like:
$ gdb ./winsleep
GNU gdb (GDB) (Cygwin 15.2-1) 15.2
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-cygwin".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./winsleep...
(gdb) run
Starting program: /home/yano/winsleep
[New Thread 49324.0x14178]
[Thread 49324.0x14178 exited with code 0]
[Inferior 1 (process 49324) exited normally]
(gdb) run
Starting program: /home/yano/winsleep
0 [] gdb 294 fhandler_pty_slave::setup_pseudoconsole: CreatePseudoConsole() failed. 00000057 80070057
[New Thread 86480.0xfd4]
[Thread 86480.0xfd4 exited with code 0]
[Inferior 1 (process 86480) exited normally]
(gdb)
The essential problem is lack of restoring nat handles for *ALL* the
PTY-slave instances after closing pseudo console in GDB.
Restoring handles from pseudo console handles to simple pipe handles
is not necessary in normal non-cygwin apps because pseudo console is
setup in the stub process for the non-cygwin app and the stub process
exits after the app is terminated.
However, for GDB, pseudo console is setup in GDB process in hooked
CreateProcess() because GDB does not use exec() to run an inferior
(debuggee). Therefore, after the inferior exits, nat handle must be
restored to simple pipe handles.
The current code restores only handles in the PTY-slave instance
that has called fhandler_pty_slave::reset_switch_to_nat_pipe(). If
this instance is different from the instance that will setup pseudo
console, the nat handles are not restored correctly, then call to
CreatePseudoConsole() causes error.
To solve this issue, restore nat handles in all the PTY-slave
instances to simple pipe handles when the inferior exits with this
patch.
In addition, if ctty is PTY-slave, fixup handles in it as well.
Fixes: 8aeb3f3e5037 ("Cygwin: pty: Make apps using console APIs be able to debug with gdb.")
Co-authored-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
Reviewed-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Diff:
---
winsup/cygwin/fhandler/pty.cc | 68 +++++++++++++++++++--------------
winsup/cygwin/local_includes/fhandler.h | 1 +
2 files changed, 41 insertions(+), 28 deletions(-)
diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc
index 14e355ce5..60b8256f4 100644
--- a/winsup/cygwin/fhandler/pty.cc
+++ b/winsup/cygwin/fhandler/pty.cc
@@ -1134,6 +1134,8 @@ fhandler_pty_slave::reset_switch_to_nat_pipe (void)
else
hand_over_only (get_ttyp ());
ReleaseMutex (pipe_sw_mutex);
+
+ HANDLE input_handle_nat, output_handle_nat;
if (need_restore_handles)
{
pinfo p (get_ttyp ()->master_pid);
@@ -1141,16 +1143,15 @@ fhandler_pty_slave::reset_switch_to_nat_pipe (void)
OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->dwProcessId);
if (pty_owner)
{
- CloseHandle (get_handle_nat ());
DuplicateHandle (pty_owner,
get_ttyp ()->from_master_nat (),
- GetCurrentProcess (), &get_handle_nat (),
+ GetCurrentProcess (),
+ &input_handle_nat,
0, TRUE, DUPLICATE_SAME_ACCESS);
- CloseHandle (get_output_handle_nat ());
DuplicateHandle (pty_owner,
get_ttyp ()->to_master_nat (),
GetCurrentProcess (),
- &get_output_handle_nat (),
+ &output_handle_nat,
0, TRUE, DUPLICATE_SAME_ACCESS);
CloseHandle (pty_owner);
}
@@ -1170,11 +1171,12 @@ fhandler_pty_slave::reset_switch_to_nat_pipe (void)
CloseHandle (repl.to_master); /* not used. */
CloseHandle (repl.to_slave_nat); /* not used. */
CloseHandle (repl.to_slave); /* not used. */
- CloseHandle (get_handle_nat ());
- set_handle_nat (repl.from_master_nat);
- CloseHandle (get_output_handle_nat ());
- set_output_handle_nat (repl.to_master_nat);
+ input_handle_nat = repl.from_master_nat;
+ output_handle_nat = repl.to_master_nat;
}
+
+ /* Restore nat handles in all pty slave instances */
+ replace_nat_handles (input_handle_nat, output_handle_nat);
}
myself->exec_dwProcessId = 0;
isHybrid = false;
@@ -3613,26 +3615,8 @@ fhandler_pty_slave::setup_pseudoconsole ()
while (false);
skip_create:
- do
- {
- /* Fixup handles */
- HANDLE orig_input_handle_nat = get_handle_nat ();
- HANDLE orig_output_handle_nat = get_output_handle_nat ();
- cygheap_fdenum cfd (false);
- while (cfd.next () >= 0)
- if (cfd->get_device () == get_device ())
- {
- fhandler_base *fh = cfd;
- fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
- if (ptys->get_handle_nat () == orig_input_handle_nat)
- ptys->set_handle_nat (hpConIn);
- if (ptys->get_output_handle_nat () == orig_output_handle_nat)
- ptys->set_output_handle_nat (hpConOut);
- }
- CloseHandle (orig_input_handle_nat);
- CloseHandle (orig_output_handle_nat);
- }
- while (false);
+ /* Fixup handles in all PTY-slave instances */
+ replace_nat_handles (hpConIn, hpConOut);
if (!process_alive (get_ttyp ()->nat_pipe_owner_pid))
get_ttyp ()->nat_pipe_owner_pid = myself->exec_dwProcessId;
@@ -4476,3 +4460,31 @@ fhandler_pty_common::tcdrain ()
cygwait (10);
return 0;
}
+
+void
+fhandler_pty_slave::replace_nat_handles (HANDLE new_input, HANDLE new_output)
+{
+ HANDLE orig_input_handle_nat = get_handle_nat();
+ HANDLE orig_output_handle_nat = get_output_handle_nat();
+ cygheap_fdenum cfd (false);
+ while (cfd.next () >= 0)
+ if (cfd->get_device () == get_device ())
+ {
+ fhandler_base *fh = cfd;
+ fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+ if (ptys->get_handle_nat () == orig_input_handle_nat)
+ ptys->set_handle_nat (new_input);
+ if (ptys->get_output_handle_nat () == orig_output_handle_nat)
+ ptys->set_output_handle_nat (new_output);
+ }
+ if (cygheap->ctty->get_device () == get_device ())
+ {
+ fhandler_pty_slave *ptys = (fhandler_pty_slave *) cygheap->ctty;
+ if (ptys->get_handle_nat () == orig_input_handle_nat)
+ ptys->set_handle_nat (new_input);
+ if (ptys->get_output_handle_nat () == orig_output_handle_nat)
+ ptys->set_output_handle_nat (new_output);
+ }
+ CloseHandle (orig_input_handle_nat);
+ CloseHandle (orig_output_handle_nat);
+}
diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h
index 5d3bf5eca..974e39698 100644
--- a/winsup/cygwin/local_includes/fhandler.h
+++ b/winsup/cygwin/local_includes/fhandler.h
@@ -2530,6 +2530,7 @@ class fhandler_pty_slave: public fhandler_pty_common
DWORD force_switch_to = 0);
void setpgid_aux (pid_t pid);
static void release_ownership_of_nat_pipe (tty *ttyp, fhandler_termios *fh);
+ void replace_nat_handles (HANDLE new_input, HANDLE new_output);
};
#define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
More information about the Cygwin-cvs
mailing list