[newlib-cygwin] Cygwin: pty: Restore nat handles in all PTY-slave instances in GDB

Takashi Yano via Cygwin-cvs <[email protected]> Mon, 6 Apr 2026 12:18:48 +0000 (GMT)
Newsgroups gmane.os.cygwin.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=3Dnewlib-cygwin.git;h=3Dc8f08427661=
b1f054e2fed93b4c1ce5ad00d882e

commit c8f08427661b1f054e2fed93b4c1ce5ad00d882e
Author: Takashi Yano <[email protected]>
Date:   Sun Mar 8 20:00:44 2026 +0900

    Cygwin: pty: Restore nat handles in all PTY-slave instances in GDB
   =20
    If non-cygwin app is started in GDB and terminating it normally,
    re-running the non-cygwin app might fail in setup_pseudoconsole().
   =20
    The error is something like:
   =20
    $ 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/>.
   =20
    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: CreatePseud=
oConsole() failed. 00000057 80070057
                               [New Thread 86480.0xfd4]
    [Thread 86480.0xfd4 exited with code 0]
    [Inferior 1 (process 86480) exited normally]
    (gdb)
   =20
    The essential problem is lack of restoring nat handles for *ALL* the
    PTY-slave instances after closing pseudo console in GDB.
   =20
    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.
   =20
    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.
   =20
    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.
   =20
    To solve this issue, restore nat handles in all the PTY-slave
    instances to simple pipe handles when the inferior exits with this
    patch.
   =20
    In addition, if ctty is PTY-slave, fixup handles in it as well.
   =20
    Fixes: 8aeb3f3e5037 ("Cygwin: pty: Make apps using console APIs be able=
 to debug with gdb.")
    Co-authored-by: Johannes Schindelin <[email protected]>
    Signed-off-by: Takashi Yano <[email protected]>
    Reviewed-by: Johannes Schindelin <[email protected]>

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 =3D repl.from_master_nat;
+		      output_handle_nat =3D repl.to_master_nat;
 		    }
+
+		  /* Restore nat handles in all pty slave instances */
+		  replace_nat_handles (input_handle_nat, output_handle_nat);
 		}
 	      myself->exec_dwProcessId =3D 0;
 	      isHybrid =3D false;
@@ -3613,26 +3615,8 @@ fhandler_pty_slave::setup_pseudoconsole ()
   while (false);
=20
 skip_create:
-  do
-    {
-      /* Fixup handles */
-      HANDLE orig_input_handle_nat =3D get_handle_nat ();
-      HANDLE orig_output_handle_nat =3D get_output_handle_nat ();
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >=3D 0)
-	if (cfd->get_device () =3D=3D get_device ())
-	  {
-	    fhandler_base *fh =3D cfd;
-	    fhandler_pty_slave *ptys =3D (fhandler_pty_slave *) fh;
-	    if (ptys->get_handle_nat () =3D=3D orig_input_handle_nat)
-	      ptys->set_handle_nat (hpConIn);
-	    if (ptys->get_output_handle_nat () =3D=3D 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);
=20
   if (!process_alive (get_ttyp ()->nat_pipe_owner_pid))
     get_ttyp ()->nat_pipe_owner_pid =3D 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_outp=
ut)
+{
+  HANDLE orig_input_handle_nat =3D get_handle_nat();
+  HANDLE orig_output_handle_nat =3D get_output_handle_nat();
+  cygheap_fdenum cfd (false);
+  while (cfd.next () >=3D 0)
+    if (cfd->get_device () =3D=3D get_device ())
+      {
+	fhandler_base *fh =3D cfd;
+	fhandler_pty_slave *ptys =3D (fhandler_pty_slave *) fh;
+	if (ptys->get_handle_nat () =3D=3D orig_input_handle_nat)
+	  ptys->set_handle_nat (new_input);
+	if (ptys->get_output_handle_nat () =3D=3D orig_output_handle_nat)
+	  ptys->set_output_handle_nat (new_output);
+      }
+  if (cygheap->ctty->get_device () =3D=3D get_device ())
+    {
+      fhandler_pty_slave *ptys =3D (fhandler_pty_slave *) cygheap->ctty;
+      if (ptys->get_handle_nat () =3D=3D orig_input_handle_nat)
+	ptys->set_handle_nat (new_input);
+      if (ptys->get_output_handle_nat () =3D=3D 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 =3D 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);
 };
=20
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))