[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