[newlib-cygwin/cygwin-3_6-branch] Cygwin: pty: Prevent unintended conversion for cursor position report

Takashi Yano via Cygwin-cvs <[email protected]> Tue, 23 Jun 2026 01:14:13 +0000 (GMT)
Newsgroups gmane.os.cygwin.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=3Dnewlib-cygwin.git;h=3D1c5c82a215a=
bcd44e5d82ee4128c468baf20821f

commit 1c5c82a215abcd44e5d82ee4128c468baf20821f
Author: Takashi Yano <[email protected]>
Date:   Mon Jun 8 22:21:19 2026 +0900

    Cygwin: pty: Prevent unintended conversion for cursor position report
   =20
    When the cursor position report ("CSI m;n R") is transferred from
    cyg-pipe to nat-pipe, it is undesirably converted into Fn3 key by
    pseudo console. This patch adds a workaround to prevent this
    unintended conversion for cursor position report by enabling
    ENABLE_VIRTUAL_TERMINAL_INPUT flag temporarily.
   =20
    Addresses: https://cygwin.com/pipermail/cygwin/2026-June/259776.html
    Reported-by: Koichi Murase <[email protected]>
    Signed-off-by: Takashi Yano <[email protected]>
    Reviewed-by: Mark Geisert <[email protected]>
    (cherry picked from commit ad65bc9742f2c232a2b8744f69fc31923965d768)

Diff:
---
 winsup/cygwin/fhandler/pty.cc      | 53 ++++++++++++++++++++++++++++++++++=
+++-
 winsup/cygwin/local_includes/tty.h |  1 +
 2 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc
index f21647718..c3895aac8 100644
--- a/winsup/cygwin/fhandler/pty.cc
+++ b/winsup/cygwin/fhandler/pty.cc
@@ -2251,7 +2251,6 @@ fhandler_pty_master::write (const void *ptr, size_t l=
en)
 	      ixput =3D 0;
 	      state =3D 0;
 	      wp_tid =3D 0;
-	      get_ttyp ()->req_xfer_input =3D false;
 	      get_ttyp ()->pcon_start =3D false;
 	      break;
 	    }
@@ -2265,6 +2264,20 @@ fhandler_pty_master::write (const void *ptr, size_t =
len)
 	      && pp && pp->pgid =3D=3D get_ttyp ()->getpgid ()
 	      && get_ttyp ()->pty_input_state_eq (tty::to_cyg))
 	    {
+	      if (!get_ttyp ()->req_xfer_input)
+		{
+		  HANDLE pcon_handle_ready_event =3D
+		    get_ttyp ()->pcon_handle_ready_event;
+		  get_handle_from_process (get_ttyp ()->nat_pipe_owner_pid,
+					   pcon_handle_ready_event);
+		  if (pcon_handle_ready_event)
+		    {
+		      cygwait (pcon_handle_ready_event, INFINITE);
+		      ResetEvent (pcon_handle_ready_event);
+		      CloseHandle (pcon_handle_ready_event);
+		    }
+		}
+
 	      /* This accept_input() call is needed in order to transfer input
 		 which is not accepted yet to non-cygwin pipe. */
 	      WaitForSingleObject (input_mutex, mutex_timeout);
@@ -2278,6 +2291,7 @@ fhandler_pty_master::write (const void *ptr, size_t l=
en)
 	      release_attach_mutex ();
 	      ReleaseMutex (input_mutex);
 	    }
+	  get_ttyp ()->req_xfer_input =3D false;
 	  get_ttyp ()->pcon_start_pid =3D 0;
 	}
       if (len =3D=3D 0)
@@ -3567,6 +3581,8 @@ fhandler_pty_slave::setup_pseudoconsole ()
       si.StartupInfo.hStdOutput =3D NULL;
       si.StartupInfo.hStdError =3D NULL;
=20
+      get_ttyp ()->pcon_handle_ready_event =3D
+	CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
       get_ttyp ()->pcon_activated =3D true;
       get_ttyp ()->pcon_start =3D true;
       get_ttyp ()->pcon_start_pid =3D myself->pid;
@@ -3653,6 +3669,7 @@ skip_create:
       /* Discard the pseudo console handler container here.
 	 Reconstruct it temporary when it is needed. */
       HeapFree (GetProcessHeap (), 0, hp);
+      SetEvent (get_ttyp ()->pcon_handle_ready_event);
     }
=20
   acquire_attach_mutex (mutex_timeout);
@@ -3860,6 +3877,11 @@ fhandler_pty_slave::close_pseudoconsole (tty *ttyp, =
DWORD force_switch_to)
 	  ttyp->pcon_start =3D false;
 	  ttyp->pcon_start_pid =3D 0;
 	}
+      if (ttyp->pcon_handle_ready_event)
+	{
+	  CloseHandle (ttyp->pcon_handle_ready_event);
+	  ttyp->pcon_handle_ready_event =3D NULL;
+	}
     }
   else
     { /* Just detach from the pseudo console if I am not owner. */
@@ -4108,6 +4130,26 @@ fhandler_pty_slave::transfer_input (tty::xfer_dir di=
r, HANDLE from, tty *ttyp,
=20
   UINT cp_from =3D 0, cp_to =3D 0;
=20
+  HANDLE h_pcon_in =3D NULL;
+  DWORD con_mode =3D 0;
+  if (ttyp->pcon_activated && dir =3D=3D tty::to_nat)
+    {
+      /* Escape sequences such as the cursor position report ("CSI m;n R")
+	 are undesirably converted into an Fn3 key by pseudo console.
+	 To privent this unintended conversion, temporarily enable
+	 ENABLE_VIRTUAL_TERMINAL_INPUT flag. */
+      h_pcon_in =3D
+	get_handle_from_process (ttyp->nat_pipe_owner_pid, ttyp->h_pcon_in);
+      if (h_pcon_in)
+	{
+	  DWORD target_pid =3D ttyp->nat_pipe_owner_pid;
+	  DWORD resume_pid =3D attach_console_temporarily (target_pid);
+	  GetConsoleMode (h_pcon_in, &con_mode);
+	  SetConsoleMode (h_pcon_in, con_mode | ENABLE_VIRTUAL_TERMINAL_INPUT);
+	  resume_from_temporarily_attach (resume_pid);
+	}
+    }
+
   if (dir =3D=3D tty::to_nat)
     {
       cp_from =3D ttyp->term_code_page;
@@ -4222,6 +4264,15 @@ fhandler_pty_slave::transfer_input (tty::xfer_dir di=
r, HANDLE from, tty *ttyp,
     }
   CloseHandle (to);
=20
+  if (h_pcon_in)
+    {
+      DWORD target_pid =3D ttyp->nat_pipe_owner_pid;
+      DWORD resume_pid =3D attach_console_temporarily (target_pid);
+      SetConsoleMode (h_pcon_in, con_mode);
+      resume_from_temporarily_attach (resume_pid);
+      CloseHandle (h_pcon_in);
+    }
+
   ttyp->pty_input_state =3D dir;
   /* Fix input_available_event which indicates availability in cyg pipe. */
   if (dir =3D=3D tty::to_nat) /* all data is transfered to nat pipe,
diff --git a/winsup/cygwin/local_includes/tty.h b/winsup/cygwin/local_inclu=
des/tty.h
index 6e70a74cd..a03e965e4 100644
--- a/winsup/cygwin/local_includes/tty.h
+++ b/winsup/cygwin/local_includes/tty.h
@@ -120,6 +120,7 @@ private:
   pid_t pcon_start_pid;
   bool switch_to_nat_pipe;
   DWORD nat_pipe_owner_pid;
+  HANDLE pcon_handle_ready_event;
   UINT term_code_page;
   ULONGLONG fwd_last_time;
   bool fwd_not_empty;