Rebase to Cygwin runtime v3.6.9#130
Merged
dscho merged 111 commits intogit-for-windows:mainfrom Apr 25, 2026
Merged
Conversation
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
In Windows 11, it seems that conhost.exe crashes on WriteFile() of zero-length data to to_slave_nat. This patch skip WriteFile() if the data length is 0. Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
In Windows 11, pseudo console uses CSI?9001h which lets the terminal enter win32-input-mode in console. As a result, two problems happen. 1) If non-cygwin app is running in script command on the console, Ctrl-C terminates not only the non-cygwin app, but also script command without cleanup for the pseudo console. 2) Some remnants sequences from win32-input-mode occasionally appears on the shell in script command on the console. This patch fixes them by omit CSI?9001h to prevent the terminal from entering win32-input-mode. Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Suggested-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
If the native (non-cygwin) app is started as background process, the input should be kept in to_cyg mode because input data should go to the cygwin shell that start the non-cygwin app. However, currently it is switched to to_nat mode in a short time and reverted to to_cyg mode just after that. With this patch, to avoid this behaviour, switching to to_nat mode is inhibited by checking PGID of the process, that is newly created for a background process and differs from PGID of the tty. Fixes: Fixes: 9fc746d ("Cygwin: pty: Fix transferring type-ahead input between input pipes.") Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> (cherry picked from commit db6269c2aee5f797cb8e2c71ac902e50acd29b20)
Previously, CSI6n was not handled correctly if the some sequences are appended after the response for CSI6n. Especially, if the appended sequence is a ESC sequence, which is longer than the expected maximum length of the CSI6n response, the sequence will not be written atomically. Moreover, 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. Due to this behaviour, the chance of code conversion to the terminal code page for the subsequent data in `to_be_read_from_nat_pipe()` case, will be lost. 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. Fixes: f206417 ("Cygwin: pty: Reduce unecessary input transfer.") Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Co-authored-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> (cherry picked from commit b4942fffd91cb91ea040bfb2778761cc6663a2b2)
The nat pipe ownership hand-over mechanism relies on the console process list - the set of processes attached to a console, enumerable via `GetConsoleProcessList()`. For non-cygwin process in pcon_activated case, this list contains all processes attached to the pseudo console. Otherwise, it contains all processes attached to the invisible console. 04f386e (Cygwin: console: Inherit pcon hand over from parent pty, 2024-10-31) added a last-resort fallback in `get_winpid_to_hand_over()` that hands nat pipe ownership to any process in the console process list, including Cygwin processes. This fallback is needed when a Cygwin process on the pseudo console (that might be exec'ed from non- cygwin process) must take over management of an active pseudo console after the original owner exits. When the pseudo console is disabled, this fallback incorrectly finds a Cygwin process (such as the shell) and assigns it nat pipe ownership, because both the original nat pipe owner and the shell are assosiated with the same invisible console. Since there is no console for that process to manage, ownership never gets released, input stays stuck on the nat pipe. Only the third (last-resort) call in the cascade needs guarding: the first two calls filter for native (non-Cygwin) processes via the `nat` parameter, and handing ownership to another native process is fine regardless of pcon state. It is only the fallback to Cygwin processes that is dangerous without an active pseudo console. Guard the fallback with a `pcon_activated` check, since handing nat pipe ownership to a Cygwin process only makes sense when there is an active pseudo console for it to manage. Fixes: 04f386e ("Cygwin: console: Inherit pcon hand over from parent pty") Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> (cherry picked from commit d1129facdc50a2968925dbbad64c03bde298ef67)
The current code waits for `sendsig` by `for` loop in sigproc.cc,
however, the wait time might be insufficient for recent CPU.
The current code is as follows.
for (int i = 0; !p->sendsig && i < 10000; i++)
yield ();
Due to this problem, in tcsh, the following command occasionally
cannot be terminated by Ctrl-C. This is because, SIGCONT does not
wake-up `sleep` process correctly.
$ cat | sleep 100 &
$ fg
$ (type Ctrl-C)
With this patch, the wait time for `sendsig` is guaranteed to be
up to 100ms instead of looping for 10000 times.
Fixes: d584454 ("* sigproc.cc (sig_send): Wait for dwProcessId to be non-zero as well as sendsig.")
Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
Reviewed-by: Corinna Vinschen <corinna@vinschen.de>
(cherry picked from commit f65c9f0c44444689b732a61ea37589293f70ae64)
Waiting for `sendsig` to be non-zero for non-cygwin process is pointless, because it never becomes non-zero (see spawn.cc). Do not wait `sendsig` for a non-cygwin process. Fixes: d584454 ("* sigproc.cc (sig_send): Wait for dwProcessId to be non-zero as well as sendsig.") Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Corinna Vinschen <corinna@vinschen.de> (cherry picked from commit 90556ffea1b6c005333066630e548839bed2cbbf)
Currently, the following command in bash cannot make `cat | cmd` foreground correctly, and also cannot be terminated by Ctrl-C. $ cat |cmd & $ fg $ (Ctrl-C) This is because, bash does not recognize the process `cmd` as stopped by SIGTTIN, and does not send SIGCONT not only to `cmd` but also to `cat`. To solve this problem, this patch implements fake stop/cont for non- cygwin process such as `cmd`. Even with this patch, the process `cmd` does not enter into stopped state because non-cygwin process itself does not handle cygwin signal, but the stub process for `cmd` enters into stopped state instead by SIGTTIN. Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Corinna Vinschen <corinna@vinschen.de> (cherry picked from commit f02f97a626aa69433651de7ce7a65f3efc010a77)
"CSI?1004h" is the sequence that enables focus event report. This can be handle correctly by pseudo console, however, if the pty input is not connected to pseudo console, the focus event responses such as "CSI I/O" are sent to the foreground process. Due to this, `cat` receives these responses unexpectedly in the command below. $ cmd & $ cat This seems to happen since Windows 11. To avoid this, this patch removes "CSI?1004h/l" from pseudo console output. Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Corinna Vinschen <corinna@vinschen.de>
Currently, the first transfer_input() after Ctrl-C does not work because discard_input flag remains asserted. This can cause loosing typeahead input for non-cygwin app after Ctrl-C. With this patch, the discard_input flag is cleared on master write() because the input is new valid input after discarding input. Fixes: 4e16e57 ("Cygwin: pty: Discard input already accepted on interrupt.") Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Corinna Vinschen <corinna@vinschen.de> (cherry picked from commit 50a87729d603cf7bf959f8cffc80371527a0537a)
Currently, pipe_sw_mutex is held in the process which is running in console inherited from pseudo console until the process ends. Due to this behaviour, the process may cause deadlock when it attempts to acquire input_mutex in set_input_mode() called via close_ctty(). This deadlock occurs because the pty master acquire input_mutex first and acquire pipe_sw_mutex next while the process exiting acquire pipe_sw_mutex first. To avoid this deadlock, this patch releases pipe_sw_mutex in pcon_hand_over_proc(). In addition, pointless pipe_sw_mutex acquire/release is drppped in pcon_hand_over_proc(). Fixes: 04f386e ("Cygwin: console: Inherit pcon hand over from parent pty") Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Corinna Vinschen <corinna@vinschen.de> (cherry picked from commit 9ef8e3ad3bec51afddb26e472857962bd1b028e3)
Cygwin maintains POSIX line discipline for its own processes: input goes through `line_edit()` before reaching the reading process. Native (non-Cygwin) processes must not receive line-edited input; they expect raw console input instead. To support both, the PTY keeps two independent pipe pairs for input: a "cyg" pipe for Cygwin processes and a "nat" pipe for native ones. The runtime switches between the two as the foreground process changes. The PTY tracks which process "owns" the nat pipe session via the shared-memory field `nat_pipe_owner_pid`. Only one process is the owner at any time. When `setup_for_non_cygwin_app()` finds that the current owner is still alive, it leaves ownership with that process rather than claiming it for the new one. This means that a Cygwin-spawned native process can go through `cleanup_for_non_cygwin_app()` without being the nat pipe owner. Before this fix, that cleanup called `transfer_input(to_cyg)` unconditionally, draining the pseudo console's input buffer even though another process still owned the session. Keystrokes that the user had typed were moved to the cyg pipe prematurely, so the actual owner found an empty console input buffer and appeared to lose all input. When looking for the next owner of the console in `cleanup_for_non_cygwin_app()` (via `get_winpid_to_hand_over()`), and when transferring the input back to the cyg pipe, guard both with a `nat_pipe_owner_self()` check so that only the actual owner performs these operations. Non-owner processes skip straight to detaching from the pseudo console without disturbing the input buffer. Fixes: f9542a2 ("Cygwin: pty: Re-fix the last bug regarding nat-pipe.") Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> (cherry picked from commit b790b19dccb7b93f2ec78dbc8353f6da58776083)
In Windows 11, key event with wRepeatCount == 0 is fixed-up to wRepeatCount == 1 in conhost.exe. https://github.com/microsoft/terminal/blob/v1.25.622.0/src/host/inputBuffer.cpp#L406 The console master thread (`cons_master_thread`) reads INPUT_RECORDs from the console input buffer, processes signal-generating events, and writes the remaining records back. After the writeback, it peeks the buffer and uses `inrec_eq()` to verify that conhost stored the records faithfully. On Windows 11, conhost normalizes `wRepeatCount` from 0 to 1 on readback, causing `inrec_eq()` to report a mismatch and triggering an unnecessary fixup path. Treat 0 and 1 as equivalent for comparison purposes. Addresses: git-for-windows/git#5632 Fixes: ff4440f ("Cygwin: console: Introduce new thread which handles input signal.") Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> (cherry picked from commit 95b477fb2df76beca1469decf71242c24b223ac5)
In Windows 11, pseudo console has an undesired key conversion that the Ctrl-H is translated into Ctrl-Backspace (not Backspace). The reverse VT input path in conhost's `_DoControlCharacter()` maps the byte 0x08 to a Ctrl+Backspace key event (VK_BACK with LEFT_CTRL_PRESSED and character 0x7F). This was introduced in PR #3935 (Jan 2020) to make Ctrl+Backspace delete whole words. In September 2022, PR #13894 rewrote the forward path to properly implement DECBKM (Backarrow Key Mode), but the reverse path was never updated to match, breaking the roundtrip. Due to this behaviour, inrec_eq() in cons_master_thread() fails to compare backspace/Ctrl-H events in the input record sequence. This patch is a workaround for the issue that replaces Ctrl-H with backspace (0x7f), which will be translated into Ctrl-H in pseudo console. Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> (cherry picked from commit 9ac383f5c2139107570e69a051ab06e56414f91d)
If the console is originating from pseudo console, the input into console is coming from PTY master. This is because: When the pseudo console is active, and a cygwin process is started from non-cygwin process, `cons_master_thread()` runs inside the Cygwin process that inherited the pseudo console from its parent PTY. It reads all `INPUT_RECORD`s from the console input buffer via `ReadConsoleInputW()`, processes signal-generating events (e.g. Ctrl+C), and writes the remaining records back via `WriteConsoleInputW()`. Meanwhile, the PTY master process (e.g. mintty) calls `fhandler_pty_master::write()`, which writes keystrokes to `to_slave_nat` (one end of the nat pipe). Conhost reads from the other end of that pipe, parses the byte stream through its VT input path, and inserts the resulting `INPUT_RECORD`s into the console input buffer. If `cons_master_thread()` reads the buffer and removes a signal record while conhost is simultaneously inserting new records from the PTY master's write, the verify step (`inrec_eq()`) finds records in the buffer that were not part of the original read, reports a mismatch, and enters the fixup path. That fixup path itself can disturb the record order, turning what was merely an interference into an actual problem. Acquiring the PTY's `input_mutex` in `cons_master_thread()` prevents `fhandler_pty_master::write()` from feeding new bytes into the pipe while the read-process-writeback-verify cycle is in progress. Use parent input_mutex as well as input_mutex in console device in cons_master_thread(). Fixes: 04f386e ("Cygwin: console: Inherit pcon hand over from parent pty") Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> (cherry picked from commit c4fb720afcf120a028f776dde47cacd2d91f3a14)
When keystrokes travel through the nat pipe during a native process session, they bypass POSIX line discipline entirely. When they are transferred back to the cyg pipe at cleanup (via `transfer_input(to_cyg)`), they arrive as raw bytes. If the terminal is in canonical mode at that point, VERASE and VKILL characters in those raw bytes have no effect because `line_edit()` was never applied to them. The result: backspace typed while a native process was running fails to erase the preceding character once the input reaches bash's readline. The fix applies `line_edit()` to the transferred bytes before they reach the reading process. The right place to do this is the master's forward thread (`pty_master_fwd_thread()`), because it runs in the master process alongside `fhandler_pty_master::write()` and shares access to the readahead buffer and `line_edit()` state. Calling `line_edit()` from the slave (where `transfer_input()` runs) would not work because that state belongs to the master. To coordinate: `transfer_input(to_cyg)` writes the raw bytes to the cyg pipe's slave end (`to_slave`), then signals a new cross-process event (`input_transferred_to_cyg`) and spin-waits for the forward thread to clear it. The forward thread is converted from synchronous to overlapped I/O so it can wait on both the `from_slave_nat` read completion and the transfer event simultaneously. When the event fires, it reads the transferred bytes from the cyg pipe's master end (`from_master`), processes them through `line_edit()`, and clears the event. The spin-wait in `transfer_input()` holds `input_mutex` (from its caller), which blocks `fhandler_pty_master::write()` from injecting new keystrokes until the forward thread has finished applying `line_edit()` to the transferred bytes. Fixes: 10d083c ("Cygwin: pty: Inherit typeahead data between two input pipes.") Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> (cherry picked from commit a0b38a81b9be482a0058e8f4f5477eeae2f2c012)
The master process (e.g. mintty) temporarily attaches to the pseudo console's conhost in `transfer_input()` so it can read INPUT_RECORDs via `ReadConsoleInputA()`. During that brief window, `get_console_process_id()` inside `get_winpid_to_hand_over()` calls `GetConsoleProcessList()`, which sees the master among the console's attached processes and may select it as the handover target. That is wrong because the master will detach immediately after the read. Until now, `attach_mutex` was a process-local unnamed mutex, so the slave's `get_winpid_to_hand_over()` could not serialize with the master's temporary attachment. Make `attach_mutex` a cross-process named mutex (`ATTACH_MUTEX`) shared within the PTY, and acquire it around the `get_console_process_id()` calls in `get_winpid_to_hand_over()`. This ensures the console process list enumeration never observes the master while it is temporarily attached. Fixes: 1e6c51d ("Cygwin: pty: Reorganize the code path of setting up and closing pcon.") Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> (cherry picked from commit 3adbd41f5babda5a42430fb25d9a02205c416542)
`to_be_read_from_nat_pipe()` reads several shared-memory fields (`switch_to_nat_pipe`, `pcon_activated`, `pty_input_state`) to decide whether keystrokes should go to the nat pipe. It is called from `master::write()` on every keystroke. Without synchronization, the slave can be in the middle of a pipe switch (changing these fields in `setup_for_non_cygwin_app()`, `cleanup_for_non_cygwin_app()`, or `setpgid_aux()`) while the master reads a half-updated snapshot, making an inconsistent routing decision that sends keystrokes to the wrong pipe. Guard `to_be_read_from_nat_pipe()` with `pipe_sw_mutex` so it always reads a consistent state. The spin-wait at entry handles the pseudo console initialization case: when `pipe_sw_mutex` is held by the slave during `setup_pseudoconsole()` and `pcon_start` is set, the function returns false immediately, routing keystrokes to the cyg pipe through `line_edit()` where the CSI6n response handler expects them. Acquiring `pipe_sw_mutex` inside `to_be_read_from_nat_pipe()` creates a lock ordering constraint: `master::write()` holds `input_mutex` before calling `to_be_read_from_nat_pipe()`, so the master's lock order is `input_mutex` then `pipe_sw_mutex`. Previously, `cleanup_for_non_cygwin_app()` and `setpgid_aux()` acquired `pipe_sw_mutex` first and then `input_mutex` (for `transfer_input()`), which is the reverse order and would deadlock. Restructure both functions to release `pipe_sw_mutex` before acquiring `input_mutex`, maintaining a consistent lock order throughout. Fixes: bb42852 ("Cygwin: pty: Implement new pseudo console support.") Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> (cherry picked from commit 2f705b879fac45e5cd761fad8dd7de6b388aee2a)
While a non-cygwin app has exited but the stub process has not yet
terminated, `nat_fg()` returns false because no non-cygwin app is
running. In this window, pty input goes to the cyg pipe. Due to
this, the keystroke order is swapped unexpectedly:
1) start non-cygwin app
2) press 'a' ('a' goes to nat pipe)
3) non-cygwin app exits
4) press 'b' ('b' goes to cyg pipe)
5) the stub process for non-cygwin app transfers input in nat pipe
to cyg pipe ('a' goes to cyg pipe)
6) the result in the cyg pipe is "ba"
Fix this by dropping the `nat_fg()` check from
`to_be_read_from_nat_pipe()`. The function now returns true when
`!pcon_start && switch_to_nat_pipe && !masked`. Each component has
a specific purpose:
- `!pcon_start`: keystrokes go through the CSI6n response handler
during pseudo console initialization rather than the fast path.
- `switch_to_nat_pipe`: this session-level flag stays true from
`setup_for_non_cygwin_app()` through `cleanup_for_non_cygwin_app()`,
spanning the entire native process lifetime including the post-exit
cleanup window.
- `!masked` (`TTY_SLAVE_READING` event does not exist): keystrokes
go to the Cygwin pipe when a Cygwin process is actively reading
from the slave, since that process expects POSIX-processed input.
Removing `nat_fg()` is safe because conhost's input buffer
accumulates keystrokes as INPUT_RECORDs during the post-exit
window, and `transfer_input(to_cyg)` in `cleanup_for_non_cygwin_app()`
reads them back via `ReadConsoleInputA()` and writes them to the
cyg pipe. Those transferred bytes then go through `line_edit()` in
the master's forward thread (via `input_transferred_to_cyg` from an
earlier patch in this series), ensuring proper POSIX line discipline
processing.
Additionally, add a `nat_fg()` check to the disable_pcon transfer
path in `master::write()`. That transfer moves cyg pipe data to
the nat pipe when a Cygwin child exits and a native process
regains the foreground with pcon disabled. Without pcon, there is
no conhost buffer to accumulate keystrokes (the nat pipe is a raw
pipe), so keystrokes must only go there when a native process is
genuinely in the foreground and ready to read them. The `nat_fg()`
guard prevents the transfer from stealing readline's data during
the post-exit window.
Fixes: f206417 ("Cygwin: pty: Reduce unecessary input transfer.")
Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
(cherry picked from commit 6413c19fd85bd7d6dc42368e22cebe86b730b3b6)
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: 8aeb3f3 ("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> (cherry picked from commit c8f08427661b1f054e2fed93b4c1ce5ad00d882e)
If the 'for' loop in pcon_start handling in master write() does not
break, 'ptr' and 'len' loose the chance to fixup the value. In this
case, all data in 'ptr' are processed, so the 'len' should be 0.
1 byte is consistently consumed in each iteration in the 'for' loop,
so this patch fixups 'ptr' and 'len' in every iterations instead of
fixing-up at break.
Fixes: 9d7440036580 ("Cygwin: pty: Fix handling of data after CSI6n response")
Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
Reviewed-by: Johannes Schindelin <johannes.schindelin@gmx.de>
(cherry picked from commit c8bbec4c551f9b606305d87a165909facf442e0b)
Currently, if the CSI6n response is divided into "CSI10;2" and "R", and another thread call master write() with "c", the data written to nat pipe will be interleaved like "CSI10;2cR". The first "CSI10;2" make the 'state' 1, and in state == 1, all the data written goes to 'wpbuf[]'. This may break startup of pseudo console. With this patch, the thread ID of the thread that write the first ESC char to 'wpbuf[]' is stored in 'wp_tid', and only if the thread ID matches 'wp_tid' will be written to 'wpbuf[]'. Fixes: bb42852 ("Cygwin: pty: Implement new pseudo console support.") Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Johannes Schindelin <johannes.schindelin@gmx.de> (cherry picked from commit 2fa51041ac547189a9f04e7c83466c178fe06994)
Currently, the cleanup path of setup_pseudoconsole() is missing DeleteProcThreadAttributeList() call, while microsoft's document requires that and the normal path has it. https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-initializeprocthreadattributelist This patch adds DeleteProcThreadAttributeList() call to the cleanup path. Fixes: bb42852 ("Cygwin: pty: Implement new pseudo console support.") Suggested-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Corinna Vinschen <corinna@vinschen.de> (cherry picked from commit 11a835fbe481018f7c50cee25e109df558da7ec2)
At some point in the past, GDB sets terminal pgid to inferior pid when the inferior is running. Moreover, the inferior is non-cygwin process, GDB sets the terminal pgid to windows pid of the inferior. Due to this behaviour, Ctrl-C does not work if the inferior is a non-cygwin app. This is because, the current code sends Ctrl-C to GDB only when GDB's pgid equeals to terminal pgid. This patch omit checking pgid when recognizing GDB process whose inferior is non- cygwin app. This patch also fixes the issue that the cygwin debuggee under strace cannot be terminated by Ctrl-C. In addition, to improve the readabiliby of the code, this patch introduces inline functions such as: is_foreground_special_process (), is_gdb_with_foreground_non_cygwin_inferior (), etc., instead of complicated conditions in 'if' clauses. Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> Reviewed-by: Corinna Vinschen <corinna@vinschen.de> (cherry picked from commit 10a3de565b1c26a3c600148fa6e478e3501cbbc2)
Currently, poll() sometimes returns -1 with errno == 0 if the fd is not opened. This is due to lack of setting errno when peek() fails. This patch ensure to set errno to thread_errno if peek() returns -1. Addresses: https://cygwin.com/pipermail/cygwin/2026-April/259602.html Fixes: 8382778 ("Cygwin: console: fix select() behaviour") Reported-by: Nahor <nahor.j+cygwin@gmail.com> Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Corinna Vinschen <corinna@vinschen.de> (cherry picked from commit 6a588c29b562c6da08061f68d71733c78fbfefc3)
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Cygwin's speclib doesn't handle dashes or dots. However, we are about to rename the output file name from `cygwin1.dll` to `msys-2.0.dll`. Let's preemptively fix up all the import libraries that would link against `msys_2_0.dll` to correctly link against `msys-2.0.dll` instead.
This seems to have been necessary in 2015 to address the expectations of some tests in Git's test suite, but seems no longer to be necessary?!? Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This topic branch fixes the problem where a UTF-16 command-line was converted to UTF-8 in an incorrect way (because Cygwin treated it as if it was a file name and applied some magic that is intended to allow for otherwise invalid file names on Windows). Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
msys2-runtime: restore fast path for current user primary group
Workaround certain anti-malware programs Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
AI-assisted coding is a reality nowadays, as is the all-too-common practice to toss a task over the wall to an AI coding agent and accept its outcome without even bothering to verify. To get better results with either approach (explicitly avoiding to characterize the latter to be even remotely okay), let's add an AGENTS.md file to give AI a "leg up". Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
See https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot#enabling-dependabot-version-updates-for-actions for details. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
AutoHotKey is not only a convenient way to add keyboard shortcuts for functionality (or applications) that does not come with shortcuts, but it is in general a powerful language to remote control GUI elements. We will use this language to implement a couple of automated tests that should hopefully prevent regressions as we have experienced in the past (for example, a regression that was fixed and immediately re-broken, which went unnoticed for months). So let's start by adding a library of useful functions, to be extended as needed. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
One particularly important part of Git for Windows' MSYS2 runtime is that it is used to run Git's tests, and regressions happened there: For example, the first iteration of MSYS2 runtime v3.5.5 caused plenty of hangs. This was realized unfortunately only after deploying the msys2-runtime Pacman package, and some painful vacation-time scrambling was required to revert to v3.5.4.This was realized unfortunately only after deploying the msys2-runtime Pacman package, and some painful vacation-time scrambling was required to revert to v3.5.4. To verify that this does not happen anymore, let's reuse what `setup-git-for-windows-sdk` uses in Git's very own CI: - determine the latest successful `ci-artifacts` workflow run in git-for-windows/git-sdk-64 - download its Git files and build artifacts - download its minimal-sdk - overwrite the MSYS2 runtime in the minimal-sdk - run the test suite and the assorted validations just like the `ci-artifacts` workflow (from which these jobs are copied) This obviously adds a hefty time penalty (around 7 minutes!) to every MSYS2 runtime PR in the git-for-windows org. Happily, these days we don't need many of those, and the balance between things like the v3.5.5 scramble and waiting a little longer for the CI to finish is clearly in favor of the latter. Co-authored-by: Jeremy Drake <github@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This is a forked repository... Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
AutoHotKey is not only a convenient way to add keyboard shortcuts for functionality (or applications) that does not come with shortcuts, but it is in general a powerful language to remote control GUI elements. We will use this language to implement a couple of automated tests that should hopefully prevent regressions as we have experienced in the past (for example, a regression that was fixed and immediately re-broken, which went unnoticed for months). So let's start by adding a library of useful functions, to be extended as needed. Note: As AutoHotKey is a GUI application, it does not expect to have stdout/stderr attached to it, therefore the `Info()` function added in this commit writes all the messages into `.log` files adjacent to the per-test working directories. But AutoHotKey _can_ have stdout/stderr attached to it, via redirection. In PowerShell, for example, appending `| Out-Default` to the invocation will make stdout/stderr available to AutoHotKey scripts (via the unintuitive syntax `FileAppend "text`n", "*"` (and `"**"` for stderr). The `Info()` function will detect when stdout is available and if it is, will also write to it, in addition to the `.log` file. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
ci: run Git's entire test suite
The issue reported in microsoft/git#730 was fixed, but due to missing tests for the issue a regression slipped in within mere weeks. Let's add an integration test that will (hopefully) prevent this issue from regressing again. This integration test is implement as an AutoHotKey script. It might look unnatural to use a script language designed to implement global keyboard shortcuts, but it is a quite powerful approach. While there are miles between the ease of developing AutoHotKey scripts and developing, say, Playwright tests, there is a decent integration into VS Code (including single-step debugging), and AutoHotKey's own development and community are quite vibrant and friendly. I had looked at alternatives to AutoHotKey, such as WinAppDriver, SikuliX, nut.js and AutoIt, in particular searching for a solution that would have a powerful recording feature similar to Playwright, but did not find any that is 1) mature, 2) well-maintained, 3) open source and 4) would be easy to integrate into a GitHub workflow. In the end, AutoHotKey appeared my clearest preference. So how is the test implemented? It lives in `ui-test/` and requires AutoHotKey v2 as well as Windows Terminal (the Legacy Prompt would not reproduce the problem). It then follows the reproducer I gave to the Cygwin team: 1. initialize a Git repository 2. install a `pre-commit` hook 3. this hook shall spawn a non-Cygwin/MSYS2 process in the background 4. that background process shall print to the console after Git exits 5. open a Command Prompt in Windows Terminal 6. run `git commit` 7. wait until the background process is done printing 8. press the Cursor Up key 9. observe that the Command Prompt does not react (in the test, it _does_ expect a reaction: the previous command in the command history should be shown, i.e. `git commit`) In my reproducer, I then also suggested to press the Enter key and to observe that now the "More ?" prompt is shown, but no input is accepted, until Ctrl+Z is pressed. Naturally, the test should not expect _that_ ;-) There were a couple of complications I needed to face when developing this test: - I did not find any easy macro recorder for AutoHotKey that I liked. It would not have helped much, anyway, because intentions are hard to record. - Before I realized that there is excellent AutoHotKey support in VS Code via the AutoHotKey++ and AutoHotKey Debug extensions, I struggled quite a bit to get the syntax right. - Windows Terminal does not use classical Win32 controls that AutoHotKey knows well. To capture the terminal text, we use Windows Terminal's exportBuffer action, which writes the entire scrollback to a file on a keybinding (Ctrl+Shift+F12). This requires running Windows Terminal in portable mode with a settings.json that defines the action, which the setup script takes care of. - Despite my expectations, `ExitApp` would not actually exit AutoHotKey before the spawned process exits and/or the associated window is closed. For good measure, run this test both on windows-2022 (corresponding to Windows 10) and on windows-2025 (corresponding to Windows 11). Note that this does not use the naive method to capture text from Windows Terminal, emulating mouse movements, dragging across the entire window with finicky pixel calculations for title bar height, scroll bar width and padding, then right-clicks to copy. This would be fragile: if the window geometry changes, if another window gets focus, or if the title bar height differs between OS versions, the capture silently gets the wrong text. Windows Terminal's exportBuffer action avoids all of that by writing the complete scrollback buffer to a file on a keybinding, with no dependence on pixel positions or window focus. To use it, Windows Terminal must run in portable mode with a settings.json that defines the action and keybinding. So that's what we do here. We add `setup-portable-wt.ps1`, which downloads Windows Terminal (when not already present), creates the .portable marker and writes settings.json with Ctrl+Shift+F12 bound to `exportBuffer`. It accepts a `-DestDir` parameter so CI can use `$RUNNER_TEMP` while local development uses `$TEMP`. When running inside GitHub Actions it also appends the Windows Terminal directory to `$GITHUB_PATH`. Co-authored-by: Eu-Pin Tien <eu-pin.tien@diamond.ac.uk> Assisted-by: Claude Opus 4.6 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The test logs are quite interesting to have, and not only those: In case of a fatal failure, the test directory is valuable information, too. Let's always upload them as build artifacts. For convenience, let's just reuse the `ui-tests/` directory as the place to put all of those files; Technically, we do not need the files in there that are tracked by Git, but practically speaking, it is neat to have them packaged in the same `.zip` file as the test logs and stuff. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Sometimes the logs are empty and it is highly unclear what has happened.
In such a scenario, a picture is indeed worth more than a thousand
words.
Note that this commit is more complicated than anyone would like, for
two reasons:
- While PowerShell is the right tool for the job, a PowerShell step in
GitHub Actions will pop up a Terminal window, _hiding_ what we want to
screenshot. To work around that, I tried to run things in a Bash step.
_Also_ opens a Terminal window! Node.js to the rescue.
- _Of course_ it is complicated to take a screenshot. The challenge is
to figure out the dimensions of the screen, which should be as easy as
looking at `[System.Windows.Forms.Screen]::PrimaryScreen`'s `Bounds`
attribute.
Easy peasy, right? No, it's not. Most machines nowadays have a
_ridiculous_ resolution which is why most setups have a _zoom factor_.
Getting to that factor should be trivial, by calling
`GetDeviceCaps(hDC, LOGPIXELSX)`, but that's not working in modern
Windows! There is a per-monitor display scaling ("DPI"). But even
_that_ is hard to get at, calling `GetDpiForMonitor()` will still
return 96 DPI (i.e. 100% zoom) because PowerShell is not marked as
_Per-Monitor DPI Aware_. Since we do not want to write a manifest into
the same directory as `powershell.exe` resides, we have to jump
through yet another hoop to get that.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The Ctrl+C way to interrupt run-away processes is highly important. It was recently broken in multiple ways in the Cygwin runtime (and hence also in the MSYS2 runtime). Let's add some integration tests that will catch regressions. It is admittedly less than ideal to add _integration_ tests; While imitating exactly what the end user does looks appealing at first, excellent tests impress by how quickly they allow regressions not only to be identified but also to be fixed. Even worse: all integration tests, by virtue of working in a broader environment than, say, unit tests, incur the price of sometimes catching unactionable bugs, i.e. bugs in software that is both outside of our control as well as not the target of our testing at all. Nevertheless, seeing as Cygwin did not add any unit tests for those Ctrl+C fixes (which is understandable, given how complex testing for Ctrl+C without UI testing would be), it is better to have integration tests than no tests at all. So here goes: This commit introduces a test that verifies that the MSYS2 `sleep.exe` can be interrupted when run from PowerShell in a Windows Terminal. This was broken in v3.6.0 and fixed in 7674c51 (Cygwin: console: Set ENABLE_PROCESSED_INPUT when disable_master_thread, 2025-07-01). Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This was the actual use case that was broken and necessitated the fix in 7674c51 (Cygwin: console: Set ENABLE_PROCESSED_INPUT when disable_master_thread, 2025-07-01). It does require an SSH server, which Git for Windows no longer ships. Therefore, this test uses the `sshd.exe` of OpenSSH for Windows (https://github.com/powershell/Win32-OpenSSH) in conjunction with Git for Windows' `ssh.exe` (because using OpenSSH for Windows' variant of `ssh.exe` would not exercise the MSYS2 runtime and therefore not demonstrate a regression, should it surface in the future). To avoid failing the test because OpenSSH for Windows is not available, the test case is guarded by the environment variable `OPENSSH_FOR_WINDOWS_DIRECTORY` which needs to point to a directory that contains a working `sshd.exe`. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
In the previous commit, I added a new UI test that generates a somewhat large repository for testing the clone via SSH. Since that repository is created in the test directory, that would inflate the `ui-tests` build artifact rather dramatically. So let's create the repository outside of that directory. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The fixes of 7674c51 (Cygwin: console: Set ENABLE_PROCESSED_INPUT when disable_master_thread, 2025-07-01) were unfortunately not complete; There were still a couple of edge cases where Ctrl+C was unable to interrupt processes. Let's add a demonstration of that issue. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
In 0ae6a6f (Cygwin: pipe: Fix SSH hang with non-cygwin pipe reader, 2025-06-27), a quite problematic bug was fixed where somewhat large-ish repositories could not be cloned via SSH anymore. This fix was not accompanied by a corresponding test case in Cygwin's test suite, i.e. there is no automated way to ensure that there won't be any regressions on that bug (and therefore it would fall onto end users to deal with those). This constitutes what Michael C. Feathers famously characterized as "legacy code" in his book "Working Effectively with Legacy Code": To me, legacy code is simply code without tests. I've gotten some grief for this definition. What do tests have to do with whether code is bad? To me, the answer is straightforward, and it is a point that I elaborate throughout the book: Code without tests is bad code. It doesn’t matter how well written it is; it doesn’t matter how pretty or object-oriented or well-encapsulated it is. With tests, we can change the behavior of our code quickly and verifiably. Without them, we really don’t know if our code is getting better or worse. Just to drive this point home, let me pull out Exhibit A: The bug fix in question, which is the latest (and hopefully last) commit in a _long_ chain of bug fixes that fix bugs introduced by preceding bug fixes: - 9e4d308 (Cygwin: pipe: Adopt FILE_SYNCHRONOUS_IO_NONALERT flag for read pipe., 2021-11-10) fixed a bug where Cygwin hung by mistake while piping output from one .NET program as input to another .NET program (potentially introduced by 3651990 (Cygwin: pipe: Avoid false EOF while reading output of C# programs., 2021-11-07), which was itself a bug fix). It introduced a bug that was fixed by... - fc691d0 (Cygwin: pipe: Make sure to set read pipe non-blocking for cygwin apps., 2024-03-11). Which introduced a bug that was purportedly fixed by... - 7ed9adb (Cygwin: pipe: Switch pipe mode to blocking mode by default, 2024-09-05). Which introduced a bug that was fixed by... - cbfaeba (Cygwin: pipe: Fix incorrect write length in raw_write(), 2024-11-06). Which introduced a bug that was fixed by... the SSH hang fix in 0ae6a6f (Cygwin: pipe: Fix SSH hang with non-cygwin pipe reader, 2025-06-27). There is not only the common thread here that each of these bug fixes introduced a new bug, but also the common thread that none of the commits introduced new test cases into the test suite that could potentially have helped prevent future breakages in this code. So let's at least add an integration test here. Side note: I am quite unhappy with introducing integration tests. I know there are a lot of fans out there, but I cannot help wondering whether they favor the convenience of writing tests quickly over the vast cost of making debugging any regression a highly cumbersome and unenjoyable affair (try single-stepping through a test case that requires several processes to be orchestrated in unison). Also, integration tests have the large price of introducing moving parts outside the code base that is actually to be tested, opening the door for breakages caused by software (or infrastructure, think: network glitches!) that are completely outside the power or responsibility of the poor engineer tasked with fixing the breakages. Nevertheless, I have been unable despite days of trying to wrap my head around the issue to figure out a way to reproduce the `fhandler_pipe_fifo::raw_write()` hang without involving a MINGW `git.exe` and an MSYS2/Cygwin `ssh.exe`. So: It's the best I could do with any reasonable amount of effort. It's better to have integration tests that would demonstrate regressions than not having any tests for that at all. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
On hosted GitHub Actions runners, there is always this Log window visible on the Desktop, and due to some magic logic, this window is sometimes in the foreground on the `windows-2025` runners. Let's minimize it so that it is out of the way and does not interfere with the AutoHotKey-based UI tests. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The existing UI test infrastructure only supports Windows Terminal, but the keystroke reordering bug reported in git-for-windows/git#5632 manifests most reliably in mintty, which uses a different PTY code path. To write a reproducer for that bug, we need library functions that can launch mintty and read back what it displayed. An initial attempt used mintty's `-l` flag to write a terminal log file, then read back that log with ANSI escape sequences stripped. This approach turned out to be unreliable: mintty buffers its log output, so content that is already visible on screen (such as the `$ ` prompt) may not have been flushed to the log file yet. Polling for a prompt that is already displayed but not yet logged leads to an indefinite wait. Instead, LaunchMintty() configures mintty's Ctrl+F5 keybinding to trigger the `export-html` action, which writes an HTML snapshot of the current screen to a file. This is instantaneous and always reflects exactly what is on screen. The function uses window-class enumeration to identify the newly-created mintty window among any pre-existing instances and returns its handle. CaptureBufferFromMintty() sends Ctrl+F5 to trigger the export, reads the resulting HTML file, extracts the `<body>` content, strips HTML tags, and decodes common entities to return plain text suitable for substring matching. It accepts an optional window title to activate the correct mintty instance before sending the keystroke. Note that AHK's ControlSend cannot be used here because mintty passes the raw keycodes through to the terminal session rather than interpreting them as window-level shortcuts, so WinActivate followed by Send is the only way to trigger the export action. Assisted-by: Claude Opus 4.6 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This adds an AutoHotKey test that reliably reproduces the keystroke reordering bug described at git-for-windows/git#5632 where characters typed into a bash prompt arrive in the wrong order. The root cause lies in the MSYS2 runtime's PTY input handling: when a non-MSYS2 process (such as PowerShell or cmd.exe) runs in the foreground of a PTY, the transfer_input() function in pty.cc can reorder bytes across pipe buffer boundaries. This is particularly visible when backspace characters get separated from the characters they were meant to delete. The test exploits this by launching a PowerShell process that saturates all CPU cores with tight cmd.exe loops while simultaneously running an MSYS2 sleep.exe in the foreground. While this stress process runs, the test rapidly types characters interleaved with backspaces at 1ms key delay. It walks through the full alphanumeric test string in chunks of two characters, appending two sacrificial characters (",;", chosen for visual dissimilarity with the letters so that they can be spotted very easily in the middle of the output) after each chunk followed by two backspaces to delete them. If the PTY delivers the bytes in order, the backspaces cleanly remove the ",;" and the result matches the original test string. If transfer_input() reorders bytes across buffer boundaries, the backspaces land in the wrong position and the "," or ";" characters leak through, producing visibly jumbled output like "GH,ABCDEFIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789". Using small chunks maximizes the number of buffer boundaries that the PTY must handle, which makes the reordering more dramatic and reliable across different environments. The cpu-stress.ps1 helper script uses cygpath to locate sleep.exe via its POSIX path so that the script works in both the full SDK (where MSYS2 tools live under a Git SDK directory) and in CI (where they live under C:\Program Files\Git). With the current runtime, the bug triggers on the very first iteration in every run tested. The fix for keystroke reordering that occurs when the pseudo console oscillates between creation and teardown removes a transfer_input(to_nat) call from the "non-pcon xfer" code path in master::write(). That code path was specifically added in Cygwin commit acc44e0 ("Cygwin: pty: Add missing input transfer when switch_to_pcon_in state", 2021-12-11) to fix a different input routing bug that manifested only when the pseudo console was disabled: https://inbox.sourceware.org/cygwin-patches/20211212130347.10080-1-takashi.yano@nifty.ne.jp/ That patch was in response to a report about spurious ANSI escape sequences ("ghost-typing") appearing in the terminal after quitting vim when git.exe (a native process) spawned vim.exe (a Cygwin process) with the pseudo console disabled: https://inbox.sourceware.org/cygwin-patches/nycvar.QRO.7.76.6.2112092345060.90@tvgsbejvaqbjf.bet/ git-for-windows/git#3579 The transfer was originally introduced as part of a broader effort to preserve typeahead across the two input pipes, starting with Cygwin commit 10d083c ("Cygwin: pty: Inherit typeahead data between two input pipes", 2021-01-28): https://inbox.sourceware.org/cygwin-patches/20210128032614.1678-2-takashi.yano@nifty.ne.jp/ which itself was prompted by a user report about typed characters disappearing while native programs were running: https://inbox.sourceware.org/cygwin/7e3d947e-b178-30a3-589f-b48e6003fbb3@googlemail.com/ Since removing that transfer could theoretically regress the disable_pcon scenario, extend the existing keystroke-order test to also run with MSYS=disable_pcon set. The test reuses the same RunKeystrokeTest() helper and stress command, just with fewer iterations since the disable_pcon code path is simpler and more deterministic. An early iteration of the "Fix out-of-order keystrokes" patch series had a bug where it would prevent native processes from receiving _any_ keystrokes under certain circumstances. Let's also specifically verify that this is _not_ the case, and prevent regressing on it. Takashi Yano's "Add workaround for handling of backspace when pcon enabled" patch works around a conhost.exe bug where byte 0x08 (Ctrl+H) is mapped to a Ctrl+Backspace key event, which performs word-wise deletion instead of single-character deletion. When asked how the bug was originally discovered (https://inbox.sourceware.org/cygwin-patches/c4dc071d-fa7e-ed2e-0c14-3fddb5240f1c@gmx.de/), Takashi explained that Ctrl+H on cmd.exe running in pseudo console erases a word, not a character, on Windows 11 (https://inbox.sourceware.org/cygwin-patches/20260328191514.360fed717ef42a086bac019b@nifty.ne.jp/). This was confirmed in a MinTTY session: launching cmd.exe, typing "abc" and pressing Ctrl+H deletes all three characters instead of just "c" (https://inbox.sourceware.org/cygwin-patches/463c3df7-3810-ed9a-9f7c-c2cf4fd6a7b7@gmx.de/). Add a verification step inside the existing cmd.exe test phase: after confirming the long test string arrived unjumbled, type "echo Expresso" followed by Ctrl+H and Enter. If Ctrl+H correctly deletes only the trailing "o", cmd.exe executes "echo Express" and prints "Express". If conhost.exe mistranslates the keypress into Ctrl+Backspace, the entire word "Expresso" is erased, cmd.exe runs bare "echo" and prints "ECHO is on." instead, causing the test to fail. Assisted-by: Claude Opus 4.6 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
There have been way too many regressions in Cygwin as of late, in particular in the console handling. The worst part? Many of those bugs were introduced _in bug fix patches_! Here are a bunch of tests that are designed to help Git for Windows increase confidence in upgrades to newer Cygwin versions. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Member
Author
|
/open pr The workflow run was started |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is quite a big one:
AGENTS.md(also because the original contribution was structured into a basic commit followed by a couple offixup!s for easier review)Range-diff
1: 90c6e2f = 1: 8ff94c8 Fix msys library name in import libraries
2: eb0623c = 2: 53bb5e0 Rename dll from cygwin to msys
3: 2d57400 = 3: 11aaade Add functionality for converting UNIX paths in arguments and environment variables to Windows form for native Win32 applications.
4: 3e3b14f = 4: e848126 Add functionality for changing OS name via MSYSTEM environment variables.
5: 019fb8c = 5: 95031f0 - Move root to /usr. - Change sorting mount points. - By default mount without ACLs. - Can read /etc/fstab with short mount point format.
6: 025bc50 = 6: e3afe9b Instead of creating Cygwin symlinks, use deep copy by default
7: 384856e = 7: 04cef96 Automatically rewrite TERM=msys to TERM=cygwin
8: add7911 = 8: 191e1b8 Do not convert environment for strace
9: 34d346c = 9: d95ef8a strace.cc: Don't set MSYS=noglob
10: e36f87e = 10: d515963 Add debugging for strace make_command_line
11: 42b2b9f = 11: 0f379db strace --quiet: be really quiet
12: 9dd7fc9 = 12: c260ea2 path_conv: special-case root directory to have trailing slash
13: a5545b3 = 13: 2a753ad When converting to a Unix path, avoid double trailing slashes
14: 4774fb2 = 14: ce71ac2 msys2_path_conv: pass PC_NOFULL to path_conv
15: 793bb2a = 15: b2b3e79 path-conversion: Introduce ability to switch off conversion.
16: 0fe7d40 = 16: 3b74813 dcrt0.cc: Untangle allow_glob from winshell
17: da4617d = 17: b58ab85 dcrt0.cc (globify): Don't quote literal strings differently when dos_spec
18: 17bfb25 = 18: ec43e0c Add debugging for build_argv
19: 3d7efd8 = 19: fb2eb43 environ.cc: New facility/environment variable MSYS2_ENV_CONV_EXCL
20: a7b6522 = 20: ca37d02 Introduce the
enable_pconvalue forMSYS21: f6c8e15 = 21: 33b14c0 popen: call /usr/bin/sh instead of /bin/sh
22: 4c0a1a8 = 22: d2263a9 Disable the 'cygwin' GitHub workflow
23: 79bf3a1 = 23: cd14361 CI: add a GHA for doing a basic build test
24: 54cf1de = 24: 1f25400 Set up a GitHub Action to keep in sync with Cygwin
25: 4b6770b = 25: 7a40bbe Expose full command-lines to other Win32 processes by default
26: a0c3117 = 26: 9abc090 Add a helper to obtain a function's address in kernel32.dll
27: 752cf15 ! 27: b2413eb Emulate GenerateConsoleCtrlEvent() upon Ctrl+C
@@ winsup/cygwin/exceptions.cc: details. */ macros are for access into CONTEXT, the _MC_foo ones for access into @@ winsup/cygwin/exceptions.cc: exit_sig: dosig: - if (have_execed) + if (have_execed && (ch_spawn.iscygwin () || !is_stop_or_cont (si.si_signo))) { - sigproc_printf ("terminating captive process"); - if (::cygheap->ctty)28: e841010 = 28: 5e19738 kill: kill Win32 processes more gently
29: 488d8d8 = 29: 450800b Cygwin: make option for native inner link handling.
30: b89a0ae = 30: a0d53e4 docs: skip building texinfo and PDF files
31: c3d121f = 31: b0fcf02 install-libs: depend on the "toollibs"
32: bbe177f = 32: 4e9612f POSIX-ify the SHELL variable
33: a0f611a = 33: 79885de Handle ORIGINAL_PATH just like PATH
34: 370a8b4 = 34: 2f1036a uname: allow setting the system name to CYGWIN
35: 871d236 = 35: 8fdf344 Pass environment variables with empty values
36: f29cf3d = 36: d064b00 Optionally disallow empty environment values again
37: 443ed30 = 37: 9c78766 build_env(): respect the
MSYSenvironment variable38: 306baf5 = 38: 66cfb0c Revert "Cygwin: Enable dynamicbase on the Cygwin DLL by default"
39: 35c1c7c = 39: 546c331 Avoid sharing cygheaps across Cygwin versions
40: c9aee64 = 40: adee13c uname: report msys2-runtime commit hash, too
41: 6e9c4de = 41: cb25225 Cygwin: Adjust CWD magic to accommodate for the latest Windows previews
-: ------- > 42: aa532e7 Cygwin: Fix segfault when XSAVE area sizes are unaligned
45: 520e5c9 = 43: d399a0d fixup! Add functionality for converting UNIX paths in arguments and environment variables to Windows form for native Win32 applications.
46: ea6fb84 = 44: 1c925ce Mention the extremely useful small_printf() function
47: 37e7445 = 45: 23d0d08 Allow native symlinks to non-existing targets in 'nativestrict' mode
48: 0ee34fb = 46: 38393ae WIP Handle 8-bit characters under LOCALE=C
43: 74ca85b = 47: 18a5a8a Make paths' WCS->MBS conversion explicit
50: 143d323 = 48: 28130fd msys2-runtime: restore fast path for current user primary group
51: 3502563 = 49: 5e1d3bf Change the default base address for x86_64
73: 1e0ff37 ! 50: 53b3656 Add AGENTS.md with comprehensive project context for AI agents
66: 40e2b5d ! 51: 4bd00d6 Cygwin: CI: update Actions versions
@@ Metadata ## Commit message ## Cygwin: CI: update Actions versions - Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - - [Release notes](https://github.com/actions/checkout/releases) - - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - - [Commits](https://github.com/actions/checkout/compare/v5...v6) - - Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6. - - [Release notes](https://github.com/actions/upload-artifact/releases) - - [Commits](https://github.com/actions/upload-artifact/compare/v5...v6) + Essentially, all of these major version updates bump the requirements to + Node.JS 24. Originally-authored-by: dependabot[bot] <support@github.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> @@ .github/workflows/cygwin.yml: jobs: HAS_SSH_KEY: ${{ secrets.SSH_KEY != '' }} steps: -- - uses: actions/checkout@v5 +- - uses: actions/checkout@v3 + - uses: actions/checkout@v6 # install build tools @@ .github/workflows/cygwin.yml: jobs: run: | icacls . /inheritance:r icacls . /grant Administrators:F -- - uses: actions/checkout@v5 +- - uses: actions/checkout@v3 + - uses: actions/checkout@v6 # install cygwin and build tools @@ .github/workflows/cygwin.yml: jobs: # upload test logs to facilitate investigation of problems - name: Upload test logs -- uses: actions/upload-artifact@v5 +- uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: testlogs42: 63747e4 ! 52: b72ad68 fixup! CI: add a GHA for doing a basic build test
@@ .github/workflows/build.yaml: jobs: with: name: install path: ${{ steps.msys2.outputs.msys2-location }} - - ## .github/workflows/cygwin.yml ## -@@ .github/workflows/cygwin.yml: jobs: - HAS_SSH_KEY: ${{ secrets.SSH_KEY != '' }} - - steps: -- - uses: actions/checkout@v3 -+ - uses: actions/checkout@v5 - - # install build tools - - name: Install build tools -@@ .github/workflows/cygwin.yml: jobs: - run: | - icacls . /inheritance:r - icacls . /grant Administrators:F -- - uses: actions/checkout@v3 -+ - uses: actions/checkout@v5 - - # install cygwin and build tools - - name: Install Cygwin44: ee9f333 = 53: 9e748a0 fixup! CI: add a GHA for doing a basic build test
49: ee961da < -: ------- Use MB_CUR_MAX == 6 by default
52: 7292892 = 54: 11e29af dependabot: help keeping GitHub Actions versions up to date
53: 0871d6d = 55: c18d12c Do not try to sync with Cygwin
54: 3a476d9 = 56: a85ceb4 ci: run Git's entire test suite
55: ad7fedc ! 57: 7eb77ae Start implementing UI-based tests by adding an AutoHotKey library
74: 78d4be1 ! 58: 2a344f8 amend! Start implementing UI-based tests by adding an AutoHotKey library
56: ec92134 ! 59: ae49b26 ci: add an AutoHotKey-based integration test
@@ Commit message quite a bit to get the syntax right. - Windows Terminal does not use classical Win32 controls that AutoHotKey - knows well. In particular, there is no easy way to capture the text - that is shown in the Terminal. I tried the (pretty excellent!) [OCR - for AutoHotKey](https://github.com/Descolada/OCR), but it uses UWP OCR - which does not recognize constructs like "C:\Usersunneradmin>"
ExitAppwould not actually exit AutoHotKeybefore the spawned process exits and/or the associated window is
@@ Commit message
For good measure, run this test both on windows-2022 (corresponding to
Windows 10) and on windows-2025 (corresponding to Windows 11).
Note that this does not use the naive method to capture text from
Windows Terminal, emulating mouse movements, dragging across the entire
window with finicky pixel calculations for title bar height, scroll bar
width and padding, then right-clicks to copy. This would be fragile:
if the window geometry changes, if another window gets focus, or if the
title bar height differs between OS versions, the capture silently gets
the wrong text.
Windows Terminal's exportBuffer action avoids all of that by writing the
complete scrollback buffer to a file on a keybinding, with no dependence
on pixel positions or window focus. To use it, Windows Terminal must
run in portable mode with a settings.json that defines the action and
keybinding. So that's what we do here.
We add
setup-portable-wt.ps1, which downloads Windows Terminal(when not already present), creates the .portable marker and writes
settings.json with Ctrl+Shift+F12 bound to
exportBuffer. It acceptsa
-DestDirparameter so CI can use$RUNNER_TEMPwhile localdevelopment uses
$TEMP. When running inside GitHub Actions it alsoappends the Windows Terminal directory to
$GITHUB_PATH.Co-authored-by: Eu-Pin Tien eu-pin.tien@diamond.ac.uk
Assisted-by: Claude Opus 4.6
Signed-off-by: Johannes Schindelin johannes.schindelin@gmx.de
.github/workflows/build.yaml
@@ .github/workflows/ui-tests.yml (new)$p = Get-ChildItem -Recurse "$ {env:RUNNER_TEMP}�rtifacts" | where {$_.Name -eq "msys-2.0.dll"} | Select -ExpandProperty VersionInfo | Select -First 1 -ExpandProperty FileName
+
+ cp $p "c:/Program Files/Git/usr/bin/msys-2.0.dll"
+
++ - uses: actions/checkout@v6
++ with:
++ sparse-checkout: |
++ ui-tests
++
+ - uses: actions/cache/restore@v5
+ id: restore-wt
+ with:
+ key: wt-${{ env.WT_VERSION }}
+ path: ${{ runner.temp }}/wt.zip
-+ - name: Download Windows Terminal
-+ if: steps.restore-wt.outputs.cache-hit != 'true'
-+ shell: bash
++ - name: Install and configure portable Windows Terminal
++ working-directory: ui-tests
+ run: |
-+ curl -fLo "$RUNNER_TEMP/wt.zip"
-+ https://github.com/microsoft/terminal/releases/download/v$WT_VERSION/Microsoft.WindowsTerminal_${WT_VERSION}_x64.zip
++ powershell -File setup-portable-wt.ps1 -WtVersion $env:WT_VERSION -DestDir $env:RUNNER_TEMP
+ - uses: actions/cache/save@v5
+ if: steps.restore-wt.outputs.cache-hit != 'true'
+ with:
+ key: wt-${{ env.WT_VERSION }}
+ path: ${{ runner.temp }}/wt.zip
-+ - name: Install Windows Terminal
-+ shell: bash
-+ working-directory: ${{ runner.temp }}
-+ run: |
-+ "$WINDIR/system32/tar.exe" -xf "$RUNNER_TEMP/wt.zip" &&
-+ cygpath -aw terminal-$WT_VERSION >>$GITHUB_PATH
+ - uses: actions/cache/restore@v5
+ id: restore-ahk
+ with:
@@ .github/workflows/ui-tests.yml (new)
+ cygpath -aw "$RUNNER_TEMP/ahk" >>$GITHUB_PATH
+ - uses: actions/setup-node@v6 # the hook uses node for the background process
+
-+ - uses: actions/checkout@v6
-+ with:
-+ sparse-checkout: |
-+ ui-tests
+ - name: Run UI tests
+ id: ui-tests
+ timeout-minutes: 10
@@ .github/workflows/ui-tests.yml (new)
+ $exitCode = 0
+ & "${env:RUNNER_TEMP}�hk\AutoHotKey64.exe" /ErrorStdOut /force ui-tests�ackground-hook.ahk "$PWD�g-hook" 2>&1 | Out-Default
+ if (!$?) { $exitCode = 1; echo "::error::Test failed!" } else { echo "::notice::Test log" }
-+ type bg-hook.log
+ exit $exitCode
+ - name: Show logs
+ if: always()
@@ .github/workflows/ui-tests.yml (new)
## ui-tests/.gitattributes (new) ##
@@
+.ahk eol=lf
++.ps1 eol=lf
@@ ui-tests/background-hook.ahk (new)
+; Verify that CursorUp shows the previous command
+Send('{Up}')
+Sleep 150
-+Text := CaptureTextFromWindowsTerminal()
++Text := CaptureBufferFromWindowsTerminal()
+if not RegExMatch(Text, 'git commit --allow-empty -m zOMG *$')
+ ExitWithError 'Cursor Up did not work: ' Text
+Info('Match!')
@@ ui-tests/background-hook.ahk (new)
+Sleep 50
+CleanUpWorkTree()
\ No newline at end of file
+
ui-tests/setup-portable-wt.ps1 (new)
+@@
++# Configures a portable Windows Terminal for the UI tests.
++#
++# Downloads WT if needed, then creates .portable marker and settings.json
++# with exportBuffer bound to Ctrl+Shift+F12. The export file lands in the
++# script's own directory (ui-tests/) so it gets uploaded as build artifact.
++#
++# The portable WT uses its own settings directory (next to the executable)
++# so it never touches the user's installed Windows Terminal configuration.
++
++param(
++ [string]$WtVersion = $env:WT_VERSION,
++ [string]$DestDir = $env:TEMP
++)
++
++if (-not $WtVersion) { $WtVersion = '1.22.11141.0' }
++
++$wtDir = "$DestDir erminal-$WtVersion"
++$wtExe = "$wtDir\wt.exe"
++
++# Download if the directory doesn't contain wt.exe yet
++if (-not (Test-Path $wtExe)) {
++ $wtZip = "$DestDir\wt.zip"
++ if (-not (Test-Path $wtZip)) {
++ $url = "https://github.com/microsoft/terminal/releases/download/v$WtVersion/Microsoft.WindowsTerminal_${WtVersion}_x64.zip"
++ Write-Host "Downloading Windows Terminal $WtVersion ..."
++ curl.exe -fLo $wtZip $url
++ if ($LASTEXITCODE -ne 0) { throw "Download failed" }
++ }
++ Write-Host "Extracting ..."
++ & "$env:WINDIR\system32 ar.exe" -C $DestDir -xf $wtZip
++ if ($LASTEXITCODE -ne 0) { throw "Extract failed" }
++}
++
++# Create .portable marker so WT reads settings from settings\ next to wt.exe
++$portableMarker = "$wtDir.portable"
++if (-not (Test-Path $portableMarker)) {
++ Set-Content -Path $portableMarker -Value ""
++}
++
++# Write settings.json with exportBuffer action
++$settingsDir = "$wtDir\settings"
++if (-not (Test-Path $settingsDir)) { New-Item -ItemType Directory -Path $settingsDir -Force | Out-Null }
++
++$bufferExportPath = ($PSScriptRoot + '\wt-buffer-export.txt') -replace '', '/'
++
++$settings = @"
++{
++ "`$schema": "https://aka.ms/terminal-profiles-schema",
++ "actions": [
++ {
++ "command": {
++ "action": "exportBuffer",
++ "path": "$bufferExportPath"
++ },
++ "id": "User.TestExportBuffer"
++ },
++ {
++ "command": { "action": "copy", "singleLine": false },
++ "id": "User.copy"
++ },
++ { "command": "paste", "id": "User.paste" }
++ ],
++ "copyFormatting": "none",
++ "copyOnSelect": false,
++ "defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
++ "keybindings": [
++ { "id": "User.TestExportBuffer", "keys": "ctrl+shift+f12" },
++ { "id": null, "keys": "ctrl+v" },
++ { "id": null, "keys": "ctrl+c" }
++ ],
++ "profiles": {
++ "defaults": {},
++ "list": [
++ {
++ "commandline": "%SystemRoot%\System32\WindowsPowerShell�1.0\powershell.exe",
++ "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
++ "hidden": false,
++ "name": "Windows PowerShell"
++ }
++ ]
++ },
++ "schemes": [],
++ "themes": []
++}
++"@
++
++Set-Content -Path "$settingsDir\settings.json" -Value $settings
++
++# Add WT to PATH if running in GitHub Actions
++if ($env:GITHUB_PATH) {
++ $wtDir | Out-File -Append -FilePath $env:GITHUB_PATH
++}
++
++Write-Host "Portable WT ready at: $wtDir"
++Write-Host " exportBuffer path: $bufferExportPath"
++Write-Host " exportBuffer key: Ctrl+Shift+F12"
58: 5fe6836 = 61: 98f3ccf ci(ui-tests): take a screenshot when canceled
59: 681f35e ! 62: 2886c18 ui-tests: verify that a
sleepin Windows Terminal can be interrupted