Re: [PATCH] Cygwin: pty: keep interactive console input for native programs via Cygwin

Takashi Yano <[email protected]>
Newsgroups gmane.os.cygwin.patches
Message-ID <[email protected]>
Hi Johannes,

On Mon, 20 Jul 2026 09:43:18 +0000
"Johannes Schindelin wrote:
> From: Johannes Schindelin <[email protected]>
> 
> Currently, when a native Windows program starts a Cygwin program while a
> pseudo console is active, and the Cygwin program then starts another
> native Windows program, the final program can lose access to console
> input. It then behaves as though its standard input were redirected
> instead of remaining interactive.
> 
> For example, a native `git.exe` may invoke shell aliases (i.e. execute a
> shell command) that would in turn call interactive Git commands who
> would no longer work because their standard input appeared to be
> redirected. This can be demonstrated as follows:
> 
>   git -c 'alias.console-probe=!powershell.exe -NoLogo -NoProfile -Command "
>     Write-Output ([Console]::IsInputRedirected)
>     try {
>       [void][Console]::KeyAvailable
>       exit 0
>     } catch {
>       exit 1
>     }
>   "' console-probe
> 
> Running this command with a Win32 version of `git.exe` currently prints
> `True` and exits with exit code 1. In the latest official release, where
> this bug is not present, it prints `False` and results in exit code 0.
> 
> The reason is to be fonud in the archetype code. Reminder: For each
> pseudo terminal (pty), the archetype is the shared pty fhandler that
> owns the underlying native handles and supplies them to every
> per-file-descriptor fhandler for that pty.
> 
> `open_with_arch()` calls `open()`, copies the first pty fhandler's state
> into the archetype, and then calls `open_setup()`. At that stage, pcon
> handle adoption already took place in `open_setup()`. This was not
> anticipated by 60a88896dc (Cygwin: pty: do not leak nat handles when
> adopting the pcon's in open_setup(), 2026-06-25), which tried to fix a
> leak by closing the superseded native handles as they were replaced in
> `open_setup()`.  Because `open_with_arch()` had already copied those
> handle values into the archetype, closing them invalidated the
> archetype's copies.
> 
> The archetype therefore retained stale values for those closed handles,
> which later pty fd fhandlers would inherit. If Windows reuses one of
> those values for a newly duplicated pcon handle, closing the stale value
> closes the new handle instead. The nested native program then receives
> unusable console input.
> 
> Preserve usable console input by moving the unchanged transactional pcon
> handle adoption to `open()`, before the archetype snapshot. The archetype
> then receives valid pcon handles, all pty fd fhandlers inherit live
> handles, and the superseded raw pipe handles are closed exactly once.
> 
> This commit is best viewed with `--color-moved`.
> 
> Fixes: 60a88896dce0 ("Cygwin: pty: do not leak nat handles when
>  adopting the pcon's in open_setup()")
> Assisted-by: GPT-5.6 Sol
> Signed-off-by: Johannes Schindelin <[email protected]>
> ---
>     Fix a regression on cygwin/master
>     
>     I noticed this regression in Git for Windows' fork, to which I had
>     backported the faulty commit from Cygwin's master branch.
> 
> Published-As: https://github.com/cygwingitgadget/cygwin/releases/tag/pr-8%2Fdscho%2Ffix-nat-handle-leakfix-cygwin-v1
> Fetch-It-Via: git fetch https://github.com/cygwingitgadget/cygwin pr-8/dscho/fix-nat-handle-leakfix-cygwin-v1
> Pull-Request: https://github.com/cygwingitgadget/cygwin/pull/8
> 
>  winsup/cygwin/fhandler/pty.cc | 44 +++++++++++++++++------------------
>  1 file changed, 22 insertions(+), 22 deletions(-)
> 
> diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc
> index f3df55f34..37a480933 100644
> --- a/winsup/cygwin/fhandler/pty.cc
> +++ b/winsup/cygwin/fhandler/pty.cc
> @@ -1220,26 +1220,6 @@ fhandler_pty_slave::open (int flags, mode_t)
>        release_attach_mutex ();
>      }
>  
> -  set_open_status ();
> -  return 1;
> -
> -err:
> -  if (GetLastError () == ERROR_FILE_NOT_FOUND)
> -    set_errno (ENXIO);
> -  else
> -    __seterrno ();
> -err_no_errno:
> -  termios_printf (errmsg);
> -err_no_msg:
> -  for (HANDLE **h = handles; *h; h++)
> -    if (**h && **h != INVALID_HANDLE_VALUE)
> -      CloseHandle (**h);
> -  return 0;
> -}
> -
> -bool
> -fhandler_pty_slave::open_setup (int flags)
> -{
>    if (get_ttyp ()->pcon_activated)
>      {
>        HANDLE pcon_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE,
> @@ -1255,8 +1235,8 @@ fhandler_pty_slave::open_setup (int flags)
>  				        0, TRUE, DUPLICATE_SAME_ACCESS);
>  	  if (ok_in && ok_out)
>  	    {
> -	      /* Close the cyg master-side handles open() installed before
> -		 replacing them, so they do not leak. */
> +	      /* Replace these before open_with_arch() copies them into the
> +		 archetype shared by all pty slave fhandlers. */
>  	      CloseHandle (get_handle_nat ());
>  	      CloseHandle (get_output_handle_nat ());
>  	      set_handle_nat (new_in);
> @@ -1273,6 +1253,26 @@ fhandler_pty_slave::open_setup (int flags)
>  	}
>      }
>  
> +  set_open_status ();
> +  return 1;
> +
> +err:
> +  if (GetLastError () == ERROR_FILE_NOT_FOUND)
> +    set_errno (ENXIO);
> +  else
> +    __seterrno ();
> +err_no_errno:
> +  termios_printf (errmsg);
> +err_no_msg:
> +  for (HANDLE **h = handles; *h; h++)
> +    if (**h && **h != INVALID_HANDLE_VALUE)
> +      CloseHandle (**h);
> +  return 0;
> +}
> +
> +bool
> +fhandler_pty_slave::open_setup (int flags)
> +{
>    set_flags ((flags & ~O_TEXT) | O_BINARY);
>    myself->set_ctty (this, flags);
>    report_tty_counts (this, "opened", "");
> 
> base-commit: 524d75ff73986b263161665af771cc90e55b5e01

At first glance, I thought this patch was incorrect, because open()
is only called in the process that initially opened the pty.
But that was a mistake on my part.

Since the commit 6eed1ef74869 ("Cygwin: pty: detect pcon-backed pty
for non-Cygwin-spawned children"), open() is also called when a cygwin
app is started from non-cygwin app. So open() is indeed the right
place to fix nat-handle, rather that open_setup().

In the first place, my patch b34394d456b6 ("Cygwin: pty: Fixup pty
state after a cygwin app exits") should place that logic in open().

Thanks for fixing that. Pushed to master branch.

-- 
Takashi Yano <[email protected]>
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.