[PATCH] Cygwin: pty: Improve CSI6n handling in pcon_start state
Takashi Yano
takashi.yano@nifty.ne.jp
Sat Feb 28 09:00:37 GMT 2026
Hi Johannes,
Thanks for reviewing!
On Fri, 27 Feb 2026 18:58:26 +0100 (CET)
Johannes Schindelin wrote:
> On Mon, 23 Feb 2026, Takashi Yano wrote:
>
> > Previsouly, CSI6n was not handled correctly if the some sequences
> > are appended after the responce for CSI6n. Especially, if the
> > appended sequence is a ESC sequence, which is longer than the
> > expected maximum length of the CSI6n responce, the sequence will
> > not be written atomically. With this patch, pcon_start state
> > is cleared at the end of CSI6n responce, and appended sequence
> > will be written outside of the CSI&n handling block.
>
> The idea of breaking out of the CSI 6n loop at `R` and falling through to
> the normal write paths is sound, but I think the `towrite` accounting has
> a bug, and the commit message could use some work.
>
> >
> > Fixes: f20641789427 ("Cygwin: pty: Reduce unecessary input transfer.")
> > Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
> > Reviewed-by:
> > ---
> > winsup/cygwin/fhandler/pty.cc | 20 +++++++++++++-------
> > 1 file changed, 13 insertions(+), 7 deletions(-)
> >
> > diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc
> > index 838be4a2b..c1e03db41 100644
> > --- a/winsup/cygwin/fhandler/pty.cc
> > +++ b/winsup/cygwin/fhandler/pty.cc
> > @@ -2137,6 +2137,8 @@ fhandler_pty_master::close (int flag)
> > ssize_t
> > fhandler_pty_master::write (const void *ptr, size_t len)
> > {
> > + size_t towrite = len;
> > +
> > ssize_t ret;
> > char *p = (char *) ptr;
> > termios &ti = tc ()->ti;
> > @@ -2171,6 +2173,8 @@ fhandler_pty_master::write (const void *ptr, size_t len)
> > }
> > if (state == 1)
> > {
> > + towrite--;
> > + ptr = p + i + 1;
>
> The per-byte `towrite--` only fires inside `state == 1`, so bytes before
> the ESC (which go through the `else` / `line_edit` branch) are never
> subtracted. If there happen to be N bytes before the ESC in the same
> write, `towrite` ends up N too large, and the `nat` pipe fast path reads
> past the end of the buffer.
>
> This can be fixed in a simpler way by not tracking `towrite` in the loop
> at all, and instead computing it once at the break, see below...
>
> > if (ixput < wpbuf_len)
> > wpbuf[ixput++] = p[i];
> > else
> > @@ -2184,7 +2188,10 @@ fhandler_pty_master::write (const void *ptr, size_t len)
> > else
> > line_edit (p + i, 1, ti, &ret);
> > if (state == 1 && p[i] == 'R')
> > - state = 2;
> > + {
> > + state = 2;
> > + break;
> > + }
>
>
> If you initialize `towrite = 0` and make this hunk look like this instead:
>
> if (state == 1 && p[i] == 'R')
> - state = 2;
> + {
> + state = 2;
> + towrite = len - i - 1;
> + ptr = p + i + 1;
> + break;
> + }
>
> then no per-byte bookkeeping is needed, making the entire logic a lot more
> robust, not to mention: easier on the reader's brain.
I'll adopt your idea and submit v2 patch.
> Regarding the commit message: beyond the typos ("Previsouly" =>
> "Previously", "responce" => "response" x3, "CSI&n" => "CSI 6n"), the body
> describes the bug as "the sequence will not be written atomically", but
> isn't the actual problem that bytes after the `R` terminator go through
> per-byte `line_edit` inside the CSI 6n loop and then hit `return len`
> without ever reaching the `nat` pipe fast path? In that case, it would be
> a routing problem, not an atomicity problem, and something like:
>
> Cygwin: pty: Fix data after CSI 6n response bypassing normal write paths
>
> When the terminal's CSI 6n response and subsequent data (e.g.
> keystrokes) arrive in the same write buffer, `master::write()`
> processes all of it inside the pcon_start loop and returns early.
> Bytes after the 'R' terminator go through per-byte `line_edit()` in
> that loop instead of falling through to the `nat` pipe fast path or
> the normal bulk `line_edit()` call.
>
> Fix this by breaking out of the loop when 'R' is found and letting the
> remaining data fall through to the normal write paths, which are now
> reachable because `pcon_start` has been cleared.
>
> would be potentially more accurate in describing what is going on.
>
> I am still quite fuzzy on the exact goings-on in the pty code, essentially
> cobbling it all together "on the side" because I unfortunately cannot
> afford to spend much focus on the Cygwin/MSYS2 runtime. Hopefully what I
> said above makes some sense?
Actually, sending the data which is sent to nat pipe to line_edit()
is not so wrong. The data buffered in the readahead buffer will be
routed to nat pipe if necessary in `accept_input()`.
However, in this case, the code page conversion is not apply to the
data. Therefore, "letting the remaining data fall through to the normal
write paths" is more appropriate than using line_edit().
Anyway, could you please review the v2 patch? Thanks in advance.
--
Takashi Yano <takashi.yano@nifty.ne.jp>
More information about the Cygwin-patches
mailing list