[newlib-cygwin] Cygwin: console: Fix regression in console input

Takashi Yano via Cygwin-cvs <[email protected]>
Newsgroups gmane.os.cygwin.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=9807479c90e37913900569d3a8f3b10247bf7860

commit 9807479c90e37913900569d3a8f3b10247bf7860
Author: Takashi Yano <[email protected]>
Date:   Mon Aug 3 10:41:14 2026 +0900

    Cygwin: console: Fix regression in console input
    
    The commit fac73911f5a0 ("Cygwin: console: Fix typeahead input for
    bash") introduced a bug where select() consumes some input chars in
    canonical mode, preventing read() from reading them. This is due to
    discarding input events when process_input_message() does not return
    `input_ok` even if it is called from select().
    The basic idea of that commit was making process_input_message()
    not to store processed chars into readahead buffer. This was not
    correct because the key input events were processed twice, once by
    select() and again by read(). Thus even if that commit worked as
    intended, the side effect such as input echo would be applied twice.
    
    With this patch, process_input_message() handles only the minimum
    necessary of input events in both cases, those processed by select()
    and those processed by read(). To achieve this behaviour, the function
    returns without processing when `input_ready` is already satisfied,
    or after it has processed the specified number of chars.
    
    Addresses: https://cygwin.com/pipermail/cygwin/2026-August/259915.html
    Reported-by: Steven Doerfler <[email protected]>
    Fixes: fac73911f5a0 ("Cygwin: console: Fix typeahead input for bash")
    Signed-off-by: Takashi Yano <[email protected]>
    Revewied-by: Johannes Schindelin <[email protected]>

Diff:
---
 winsup/cygwin/fhandler/console.cc | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc
index d4c87f29f..ba35ca44c 100644
--- a/winsup/cygwin/fhandler/console.cc
+++ b/winsup/cygwin/fhandler/console.cc
@@ -479,7 +479,7 @@ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp)
 	}
 
       WaitForSingleObject (p->input_mutex, mutex_timeout);
-      /* Ensure accessing input recored is not disabled. */
+      /* Ensure accessing input record is not disabled. */
       if (con.disable_master_thread)
 	{
 	  ReleaseMutex (p->input_mutex);
@@ -1331,7 +1331,6 @@ fhandler_console::input_states
 fhandler_console::process_input_message (size_t len)
 {
   char tmp[60];
-  size_t num_chars = 0;
 
   if (!shared_console_info[unit])
     return input_error;
@@ -1354,6 +1353,13 @@ fhandler_console::process_input_message (size_t len)
       return input_error;
     }
 
+  /* len == 0 if called from select.cc:peek_console() */
+  /* This code is reached only when being passed the input_ready check,
+     however, the check was done outside input_mutex. Therefore, another
+     thread may set input_ready after the check. Check it again here. */
+  if (input_ready && (len == 0 || (get_ttyp ()->ti.c_lflag & ICANON)))
+    return input_ok;
+
   for (i = 0; i < total_read; i ++)
     {
       DWORD nread = 1;
@@ -1719,7 +1725,6 @@ fhandler_console::process_input_message (size_t len)
 	}
 
       num_input_events_processed = i + 1;
-      num_chars += nread;
       if (toadd)
 	{
 	  ssize_t ret;
@@ -1738,21 +1743,17 @@ fhandler_console::process_input_message (size_t len)
 	    }
 	}
       /* len == 0 if called from select.cc:peek_console() */
-      if (len && num_chars >= len)
+      if (input_ready && (len == 0 || con_ra.ralen >= len))
 	goto out;
     }
 out:
-  if (len == 0)
-    /* If len == 0, cancel reading from console input buffer.
-       Clear readahead buffer. */
-    eat_readahead (-1);
-  /* Discard processed recored. */
+  /* Discard processed record. */
   DWORD discard_len = min (total_read, i + 1);
   /* If input is signalled, do not discard input here because
      discard_key_events() is already called from line_edit(). */
   if (stat == input_signalled)
     discard_len = 0;
-  if (discard_len && (len || stat != input_ok))
+  if (discard_len)
     discard_key_events (discard_len);
   return stat;
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.