From 9577467743aac6da917186c9c44b687847df7e3f Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Sun, 25 Aug 2024 11:59:29 +0200 Subject: [PATCH 001/116] bump DLL version to 3.5.5 Signed-off-by: Corinna Vinschen --- winsup/cygwin/include/cygwin/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index 0f87fbc27f..fb821a681b 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -11,7 +11,7 @@ details. */ changes to the DLL and is mainly informative in nature. */ #define CYGWIN_VERSION_DLL_MAJOR 3005 -#define CYGWIN_VERSION_DLL_MINOR 4 +#define CYGWIN_VERSION_DLL_MINOR 5 /* CYGWIN_VERSION_DLL_COMBINED gives us a single number representing the combined DLL major and minor numbers. */ From 68a14b66ff2dd6e71497a3a9583253d17e7e790e Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Sat, 31 Aug 2024 18:32:00 +0900 Subject: [PATCH 002/116] Cygwin: console: Disable cons_master_thread in win32-input-mode When win32-input-mode (which is supported by Windows Termainal) is set by "\033[?9001h", cons_master_thread does not work properly and consumes larger and larger memory space. This is because sending event by WriteConsoleInput() is translated into the sequence that is used by win32-input-mode. Due to this behaviour, write-back of the INPUT_RECORDs does not work as expected. With this patch, cons_master_thread is disabled on win32-input-mode where the signal keys such as Ctrl-C, Ctrl-Z etc. never comes. Addresses: https://cygwin.com/pipermail/cygwin/2024-August/256380.html Fixes: ff4440fcf768 ("Cygwin: console: Introduce new thread which handles input signal.") Reported-by: Adamyg Mob Signed-off-by: Takashi Yano (cherry picked from commit 84d77e5918e18170c393407d477140fcf5d3e432) --- winsup/cygwin/fhandler/console.cc | 8 ++++++-- winsup/cygwin/local_includes/fhandler.h | 2 ++ winsup/cygwin/release/3.5.5 | 6 ++++++ 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 winsup/cygwin/release/3.5.5 diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc index d4c3f1020b..dc43cd9f59 100644 --- a/winsup/cygwin/fhandler/console.cc +++ b/winsup/cygwin/fhandler/console.cc @@ -818,6 +818,7 @@ fhandler_console::set_input_mode (tty::cons_mode m, const termios *t, GetConsoleMode (p->input_handle, &oflags); DWORD flags = oflags & (ENABLE_EXTENDED_FLAGS | ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE); + con.curr_input_mode = m; switch (m) { case tty::restore: @@ -867,6 +868,7 @@ fhandler_console::set_output_mode (tty::cons_mode m, const termios *t, if (con.orig_virtual_terminal_processing_mode) flags |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; WaitForSingleObject (p->output_mutex, mutex_timeout); + con.curr_output_mode = m; switch (m) { case tty::restore: @@ -1109,12 +1111,12 @@ fhandler_console::bg_check (int sig, bool dontsignal) /* Setting-up console mode for cygwin app. This is necessary if the cygwin app and other non-cygwin apps are started simultaneously in the same process group. */ - if (sig == SIGTTIN) + if (sig == SIGTTIN && con.curr_input_mode != tty::cygwin) { set_input_mode (tty::cygwin, &tc ()->ti, get_handle_set ()); set_disable_master_thread (false, this); } - if (sig == SIGTTOU) + if (sig == SIGTTOU && con.curr_output_mode != tty::cygwin) set_output_mode (tty::cygwin, &tc ()->ti, get_handle_set ()); return fhandler_termios::bg_check (sig, dontsignal); @@ -2921,6 +2923,8 @@ fhandler_console::char_command (char c) } if (con.args[i] == 1) /* DECCKM */ con.cursor_key_app_mode = (c == 'h'); + if (con.args[i] == 9001) /* win32-input-mode (https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md) */ + set_disable_master_thread (c == 'h', this); } /* Call fix_tab_position() if screen has been alternated. */ if (need_fix_tab_position) diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h index 3d819f49b5..10bc9c7ec8 100644 --- a/winsup/cygwin/local_includes/fhandler.h +++ b/winsup/cygwin/local_includes/fhandler.h @@ -2160,6 +2160,8 @@ class dev_console char *cons_rapoi; bool cursor_key_app_mode; bool disable_master_thread; + tty::cons_mode curr_input_mode; + tty::cons_mode curr_output_mode; bool master_thread_suspended; int num_processed; /* Number of input events in the current input buffer already processed by cons_master_thread(). */ diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 new file mode 100644 index 0000000000..a98687c26e --- /dev/null +++ b/winsup/cygwin/release/3.5.5 @@ -0,0 +1,6 @@ +Fixes: +------ + +- Fix undesired behaviour of console master thread in win32-input-mode + which is supported by Windows Termainal. + Addresses: https://cygwin.com/pipermail/cygwin/2024-August/256380.html From 37ab3e0d55e3ff3932509bfd2f2625c138b18866 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Sun, 1 Sep 2024 04:31:03 +0900 Subject: [PATCH 003/116] Cygwin: pipe: Fix a regression that raw_write() slows down After the commit 7f3c22532577, writing to pipe extremely slows down. This is because cygwait(select_sem, 10, cw_cancel) is called even when write operation is already completed. With this patch, the cygwait() is called only if the write operation is not completed. Addresses: https://cygwin.com/pipermail/cygwin/2024-August/256398.html Fixes: 7f3c22532577 ("Cygwin: pipe: handle signals explicitely in raw_write") Reported-by: Jim Reisert AD1C Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit f78009cb1ccf84cc343cf2441c76196461d87532) --- winsup/cygwin/fhandler/pipe.cc | 6 ++++-- winsup/cygwin/release/3.5.5 | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/winsup/cygwin/fhandler/pipe.cc b/winsup/cygwin/fhandler/pipe.cc index 6658a23e7f..997346877d 100644 --- a/winsup/cygwin/fhandler/pipe.cc +++ b/winsup/cygwin/fhandler/pipe.cc @@ -503,8 +503,9 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len) raise (SIGPIPE); goto out; } - else - cygwait (select_sem, 10, cw_cancel); + /* Break out on completion */ + if (waitret == WAIT_OBJECT_0) + break; /* If we got a timeout in the blocking case, and we already did a short write, we got a signal in the previous loop. */ if (waitret == WAIT_TIMEOUT && short_write_once) @@ -512,6 +513,7 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len) waitret = WAIT_SIGNALED; break; } + cygwait (select_sem, 10, cw_cancel); } /* Loop in case of blocking write or SA_RESTART */ while (waitret == WAIT_TIMEOUT || waitret == WAIT_SIGNALED); diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index a98687c26e..904119a387 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -4,3 +4,6 @@ Fixes: - Fix undesired behaviour of console master thread in win32-input-mode which is supported by Windows Termainal. Addresses: https://cygwin.com/pipermail/cygwin/2024-August/256380.html + +- Fix a regression in 3.5.4 that writing to pipe extremely slows down. + Addresses: https://cygwin.com/pipermail/cygwin/2024-August/256398.html From 784ce7aff8c92b6b729e8bf5564e582360c24d8c Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 14 Feb 2024 14:00:34 +0100 Subject: [PATCH 004/116] Cygwin: accommodate gcc -Og option All three warnings produced with -Og are false positives. But given we're using -Werror unconditionally it's better to be safe than sorry. Reported-by: Kevin Ushey Signed-off-by: Corinna Vinschen (cherry picked from commit 2a2a6486a089b90d05b258bd853d136f00cb7c69) --- winsup/cygwin/fhandler/fifo.cc | 2 +- winsup/cygwin/tty.cc | 2 +- winsup/utils/kill.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/winsup/cygwin/fhandler/fifo.cc b/winsup/cygwin/fhandler/fifo.cc index efea508ae5..ee49ce695e 100644 --- a/winsup/cygwin/fhandler/fifo.cc +++ b/winsup/cygwin/fhandler/fifo.cc @@ -669,7 +669,7 @@ fhandler_fifo::create_shmem (bool only_open) { HANDLE sect; OBJECT_ATTRIBUTES attr; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; LARGE_INTEGER size = { .QuadPart = sizeof (fifo_shmem_t) }; SIZE_T viewsize = sizeof (fifo_shmem_t); PVOID addr = NULL; diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc index bf7c6010fd..2cd4ae6ed4 100644 --- a/winsup/cygwin/tty.cc +++ b/winsup/cygwin/tty.cc @@ -323,7 +323,7 @@ tty::wait_fwd () thread when the last data is transfered. */ const ULONGLONG sleep_in_nat_pipe = 16; const ULONGLONG time_to_wait = sleep_in_nat_pipe * 2 + 1/* margine */; - ULONGLONG elapsed; + ULONGLONG elapsed = 0; while (fwd_not_empty || (elapsed = GetTickCount64 () - fwd_last_time) < time_to_wait) { diff --git a/winsup/utils/kill.cc b/winsup/utils/kill.cc index fb45e4c9dc..bcabcd47c9 100644 --- a/winsup/utils/kill.cc +++ b/winsup/utils/kill.cc @@ -73,7 +73,7 @@ print_version () static const char * strsigno (int signo) { - static char sigbuf[8]; + static char sigbuf[32]; if (signo > 0 && signo < SIGRTMIN) return sys_sigabbrev[signo]; From c7fe29f5cb85242ae2607945762f7e0b9af02513 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Fri, 6 Sep 2024 14:19:44 +0900 Subject: [PATCH 005/116] Cygwin: pipe: Restore blocking mode of read pipe on close()/raw_read() If a cygwin app is executed from a non-cygwin app and the cygwin app exits, the read pipe remains in the non-blocking mode because of the commit fc691d0246b9. Due to this behaviour, the non-cygwin app cannot read the pipe correctly after that. Similarly, if a non-cygwin app is executed from a cygwin app and the non-cygwin app exits, the read pipe remains in the blocking mode. With this patch, the blocking mode of the read pipe is stored into a variable was_blocking_read_pipe on set_pipe_non_blocking() when the cygwin app starts and restored on close(). In addition, the pipe mode is set to non-blocking mode in raw_read() if the mode is blocking mode by referring the variable is_blocking_read_pipe as well. is_blocking_read_pipe is a member of fhandler_pipe class and is set by set_pipe_non_blocking(), so if other process sets the pipe mode to blocking mode, the current process cannot know the pipe is blocking mode. Therefore, is_blocking_read_pipe is also set on the signal __SIGNONCYGCHLD, which is sent to the process group when non-cygwin app is started. Addresses: https://github.com/git-for-windows/git/issues/5115 Fixes: fc691d0246b9 ("Cygwin: pipe: Make sure to set read pipe non-blocking for cygwin apps."); Reported-by: isaacag, Johannes Schindelin Reviewed-by: Corinna Vinschen , Ken Brown Signed-off-by: Takashi Yano --- winsup/cygwin/fhandler/pipe.cc | 41 +++++++++++++++++++++++++ winsup/cygwin/local_includes/fhandler.h | 3 ++ winsup/cygwin/sigproc.cc | 9 +----- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/winsup/cygwin/fhandler/pipe.cc b/winsup/cygwin/fhandler/pipe.cc index 997346877d..3b78cc183e 100644 --- a/winsup/cygwin/fhandler/pipe.cc +++ b/winsup/cygwin/fhandler/pipe.cc @@ -54,6 +54,16 @@ fhandler_pipe::set_pipe_non_blocking (bool nonblocking) NTSTATUS status; IO_STATUS_BLOCK io; FILE_PIPE_INFORMATION fpi; + bool was_blocking_read_pipe_new = was_blocking_read_pipe; + + if (get_device () == FH_PIPER && nonblocking && !was_blocking_read_pipe) + { + status = NtQueryInformationFile (get_handle (), &io, &fpi, sizeof fpi, + FilePipeInformation); + if (NT_SUCCESS (status)) + was_blocking_read_pipe_new = + (fpi.CompletionMode == FILE_PIPE_QUEUE_OPERATION); + } fpi.ReadMode = FILE_PIPE_BYTE_STREAM_MODE; fpi.CompletionMode = nonblocking ? FILE_PIPE_COMPLETE_OPERATION @@ -62,6 +72,11 @@ fhandler_pipe::set_pipe_non_blocking (bool nonblocking) FilePipeInformation); if (!NT_SUCCESS (status)) debug_printf ("NtSetInformationFile(FilePipeInformation): %y", status); + else + { + was_blocking_read_pipe = was_blocking_read_pipe_new; + is_blocking_read_pipe = !nonblocking; + } } int @@ -95,6 +110,8 @@ fhandler_pipe::init (HANDLE f, DWORD a, mode_t mode, int64_t uniq_id) even with FILE_SYNCHRONOUS_IO_NONALERT. */ set_pipe_non_blocking (get_device () == FH_PIPER ? true : is_nonblocking ()); + was_blocking_read_pipe = false; + return 1; } @@ -289,6 +306,9 @@ fhandler_pipe::raw_read (void *ptr, size_t& len) if (!len) return; + if (is_blocking_read_pipe) + set_pipe_non_blocking (true); + DWORD timeout = is_nonblocking () ? 0 : INFINITE; DWORD waitret = cygwait (read_mtx, timeout); switch (waitret) @@ -721,6 +741,8 @@ fhandler_pipe::close () CloseHandle (query_hdl); if (query_hdl_close_req_evt) CloseHandle (query_hdl_close_req_evt); + if (was_blocking_read_pipe) + set_pipe_non_blocking (false); int ret = fhandler_base::close (); ReleaseMutex (hdl_cnt_mtx); CloseHandle (hdl_cnt_mtx); @@ -1373,6 +1395,7 @@ fhandler_pipe::spawn_worker (int fileno_stdin, int fileno_stdout, { fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd; pipe->set_pipe_non_blocking (false); + need_send_noncygchld_sig = true; } /* If multiple writers including non-cygwin app exist, the non-cygwin @@ -1398,3 +1421,21 @@ fhandler_pipe::spawn_worker (int fileno_stdin, int fileno_stdout, t->kill_pgrp (__SIGNONCYGCHLD); } } + +void +fhandler_pipe::sigproc_worker (void) +{ + cygheap_fdenum cfd (false); + while (cfd.next () >= 0) + if (cfd->get_dev () == FH_PIPEW) + { + fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd; + if (pipe->need_close_query_hdl ()) + pipe->close_query_handle (); + } + else if (cfd->get_dev () == FH_PIPER) + { + fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd; + pipe->is_blocking_read_pipe = true; + } +} diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h index 10bc9c7ec8..000004479b 100644 --- a/winsup/cygwin/local_includes/fhandler.h +++ b/winsup/cygwin/local_includes/fhandler.h @@ -1197,6 +1197,8 @@ class fhandler_pipe: public fhandler_pipe_fifo private: HANDLE read_mtx; pid_t popen_pid; + bool was_blocking_read_pipe; + bool is_blocking_read_pipe; HANDLE query_hdl; HANDLE hdl_cnt_mtx; HANDLE query_hdl_proc; @@ -1287,6 +1289,7 @@ class fhandler_pipe: public fhandler_pipe_fifo } static void spawn_worker (int fileno_stdin, int fileno_stdout, int fileno_stderr); + static void sigproc_worker (void); }; #define CYGWIN_FIFO_PIPE_NAME_LEN 47 diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 99fa3c3425..a758bc8f2c 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -1475,14 +1475,7 @@ wait_sig (VOID *) } break; case __SIGNONCYGCHLD: - cygheap_fdenum cfd (false); - while (cfd.next () >= 0) - if (cfd->get_dev () == FH_PIPEW) - { - fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd; - if (pipe->need_close_query_hdl ()) - pipe->close_query_handle (); - } + fhandler_pipe::sigproc_worker (); break; } if (clearwait && !have_execed) From 0281d2c8e294b45a66761fb912095e16f290c556 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 23 Oct 2024 11:44:34 +0200 Subject: [PATCH 006/116] cygwin: pread/pwrite: prevent EBADF error after fork() If the parent process has already used pread() or pwrite(), these functions fail with EBADF if used on the inherited fd. Ensure that fix_after_fork() is called to invalidate the prw_handle. This issue has been detected by 'stress-ng --pseek 1'. Fixes: c36cd56c548a ("* fhandler.cc (fhandler_base::open): Drop local create_options variable.") Signed-off-by: Christian Franke --- winsup/cygwin/fhandler/disk_file.cc | 3 +++ winsup/cygwin/release/3.5.5 | 3 +++ 2 files changed, 6 insertions(+) diff --git a/winsup/cygwin/fhandler/disk_file.cc b/winsup/cygwin/fhandler/disk_file.cc index 2cfac6be1e..794c8ebcac 100644 --- a/winsup/cygwin/fhandler/disk_file.cc +++ b/winsup/cygwin/fhandler/disk_file.cc @@ -1810,6 +1810,9 @@ fhandler_disk_file::prw_open (bool write, void *aio) return -1; } + /* prw_handle is invalid after fork. */ + need_fork_fixup (true); + /* record prw_handle's asyncness for subsequent pread/pwrite operations */ prw_handle_isasync = !!aio; return 0; diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index 904119a387..d01f31c603 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -7,3 +7,6 @@ Fixes: - Fix a regression in 3.5.4 that writing to pipe extremely slows down. Addresses: https://cygwin.com/pipermail/cygwin/2024-August/256398.html + +- Fix pread() and pwrite() EBADF error after fork(). + Addresses: https://sourceware.org/pipermail/cygwin/2024-September/256468.html From 6e39f397b589539285f1772ada03b7199b3ea7a5 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 23 Oct 2024 12:24:06 +0200 Subject: [PATCH 007/116] Cygwin: timer_delete: Fix return value timer_delete() always returned failure. This issue has been detected by 'stress-ng --hrtimers 1'. Fixes: 229ea3f23c015 ("Cygwin: posix timers: reimplement using OS timer") Signed-off-by: Christian Franke --- winsup/cygwin/posix_timer.cc | 1 + winsup/cygwin/release/3.5.5 | 2 ++ 2 files changed, 3 insertions(+) diff --git a/winsup/cygwin/posix_timer.cc b/winsup/cygwin/posix_timer.cc index 9d832f2014..a336b2bc2d 100644 --- a/winsup/cygwin/posix_timer.cc +++ b/winsup/cygwin/posix_timer.cc @@ -530,6 +530,7 @@ timer_delete (timer_t timerid) __leave; } delete in_tt; + ret = 0; } __except (EFAULT) {} __endtry diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index d01f31c603..bcc2c661b7 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -10,3 +10,5 @@ Fixes: - Fix pread() and pwrite() EBADF error after fork(). Addresses: https://sourceware.org/pipermail/cygwin/2024-September/256468.html + +- Fix timer_delete() return value which always indicated failure. From db6ad93d371ce5d1f300886a3a683747e93cf12d Mon Sep 17 00:00:00 2001 From: Fabian Schriever Date: Wed, 11 Sep 2024 16:06:44 +0200 Subject: [PATCH 008/116] powf: Fix the hi+lo decomposition for 2/(3ln2) (FreeBSD) The decomposition needs to be into 12+24 bits of precision for extra- precision multiplication, but was into 13+24 bits. On i386 with -O1 the bug was hidden by accidental extra precision, but on amd64, in 2^32 trials the bug caused about 200000 errors of more than 1 ulp, with a maximum error of about 80 ulps. Now the maximum error in 2^32 trials on amd64 is 0.8573 ulps. It is still 0.8316 ulps on i386 with -O1. The nearby decomposition of 1/ln2 and the decomposition of 2/(3ln2) in the double precision version seem to be sub-optimal but not broken. Reference: https://github.com/freebsd/freebsd-src/commit/b4437c3d322a0f6d23d12b6f76d2fc72d2ff0ec2 Original Author: Bruce Evans --- newlib/libm/math/ef_pow.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/newlib/libm/math/ef_pow.c b/newlib/libm/math/ef_pow.c index 07b225f8cb..4ceba3d247 100644 --- a/newlib/libm/math/ef_pow.c +++ b/newlib/libm/math/ef_pow.c @@ -50,8 +50,8 @@ lg2_h = 6.93145752e-01, /* 0x3f317200 */ lg2_l = 1.42860654e-06, /* 0x35bfbe8c */ ovt = 4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */ cp = 9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */ -cp_h = 9.6179199219e-01, /* 0x3f763800 =head of cp */ -cp_l = 4.7017383622e-06, /* 0x369dc3a0 =tail of cp_h */ +cp_h = 9.6191406250e-01f, /* 0x3f764000 =12b of cp */ +cp_l = -1.1736857402e-04f, /* 0xb8f623c6 =tail of cp_h */ ivln2 = 1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */ ivln2_h = 1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/ ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ From f21b93098dcdda3f34d847b423c463b5630df4b9 Mon Sep 17 00:00:00 2001 From: Fabian Schriever Date: Wed, 11 Sep 2024 16:06:45 +0200 Subject: [PATCH 009/116] powf: Fixed 2 bugs in the computation /* t_h=ax+bp[k] High */. (FreeBSD) (1) The bit for the 1.0 part of bp[k] was right shifted by 4. This seems to have been caused by a typo in converting e_pow.c to e_powf.c. (2) The lower 12 bits of ax+bp[k] were not discarded, so t_h was actually plain ax+bp[k]. This seems to have been caused by a logic error in the conversion. These bugs gave wrong results like: powf(-1.1, 101.0) = -15158.703 (should be -15158.707) hex values: BF8CCCCD 42CA0000 C66CDAD0 C66CDAD4 Fixing (1) gives a result wrong in the opposite direction (hex C66CDAD8), and fixing (2) gives the correct result. ucbtest has been reporting this particular wrong result on i386 systems with unpatched libraries for 9 years. I finally figured out the extent of the bugs. On i386's they are normally hidden by extra precision. We use the trick of representing floats as a sum of 2 floats (one much smaller) to get extra precision in intermediate calculations without explicitly using more than float precision. This trick is just a pessimization when extra precision is available naturally (as it always is when dealing with IEEE single precision, so the float precision part of the library is mostly misimplemented). (1) and (2) break the trick in different ways, except on i386's it turns out that the intermediate calculations are done in enough precision to mask both the bugs and the limited precision of the float variables (as far as ucbtest can check). ucbtest detects the bugs because it forces float precision, but this is not a normal mode of operation so the bug normally has little effect on i386's. On systems that do float arithmetic in float precision, e.g., amd64's, there is no accidental extra precision and the bugs just give wrong results. Reference: https://github.com/freebsd/freebsd-src/commit/12be4e0d5a54a6750913aee2564d164baa71f0dc Original Author: Bruce Evans --- newlib/libm/math/ef_pow.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/newlib/libm/math/ef_pow.c b/newlib/libm/math/ef_pow.c index 4ceba3d247..c7b1975c38 100644 --- a/newlib/libm/math/ef_pow.c +++ b/newlib/libm/math/ef_pow.c @@ -173,7 +173,8 @@ ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ GET_FLOAT_WORD(is,s_h); SET_FLOAT_WORD(s_h,is&0xfffff000); /* t_h=ax+bp[k] High */ - SET_FLOAT_WORD(t_h,((ix>>1)|0x20000000)+0x0040000+(k<<21)); + is = ((ix >> 1) & 0xfffff000U) | 0x20000000; + SET_FLOAT_WORD(t_h, is + 0x00400000 + (k << 21)); t_l = ax - (t_h-bp[k]); s_l = v*((u-s_h*t_h)-s_h*t_l); /* compute log(ax) */ From 142c3c3ebd21d584257761995fbe00e1e3f92c49 Mon Sep 17 00:00:00 2001 From: Fabian Schriever Date: Wed, 11 Sep 2024 16:06:46 +0200 Subject: [PATCH 010/116] powf: Fixed another precision bug in powf() (FreeBSD) Fixed another precision bug in powf(). This one is in the computation [t=p_l+p_h High]. We multiply t by lg2_h, and want the result to be exact. For the bogus float case of the high-low decomposition trick, we normally discard the lowest 12 bits of the fraction for the high part, keeping 12 bits of precision. That was used for t here, but it doesnt't work because for some reason we only discard the lowest 9 bits in the fraction for lg2_h. Discard another 3 bits of the fraction for t to compensate. This bug gave wrong results like: powf(0.9999999, -2.9999995) = 1.0000002 (should be 1.0000001) hex values: 3F7FFFFF C03FFFFE 3F800002 3F800001 As explained in the log for the previous commit, the bug is normally masked by doing float calculations in extra precision on i386's, but is easily detected by ucbtest on systems that don't have accidental extra precision. Reference: https://github.com/freebsd/freebsd-src/commit/5f20e5ce7f396ad064bfc1f45b8075ea1c0580f9 Original Author: Bruce Evans --- newlib/libm/math/ef_pow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/newlib/libm/math/ef_pow.c b/newlib/libm/math/ef_pow.c index c7b1975c38..8cf58dbb54 100644 --- a/newlib/libm/math/ef_pow.c +++ b/newlib/libm/math/ef_pow.c @@ -242,7 +242,7 @@ ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ } t = p_l+p_h; GET_FLOAT_WORD(is,t); - SET_FLOAT_WORD(t,is&0xfffff000); + SET_FLOAT_WORD(t,is&0xffff8000); u = t*lg2_h; v = (p_l-(t-p_h))*lg2+t*lg2_l; z = u+v; From b76735a5719375cf9d33d63612092ff8516e99a0 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Sun, 20 Oct 2024 00:59:51 +0900 Subject: [PATCH 011/116] Cygwin: lockf: Fix adding a new lock over multiple locks Previously, adding a new lock by lockf() over multiple existing locks failed. This is due to a bug that lf_setlock() tries to create a lock that has already been created. This patch fixes the issue. Addresses: https://cygwin.com/pipermail/cygwin/2024-October/256528.html Fixes: a998dd705576 ("* flock.cc: Implement all advisory file locking here.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano --- winsup/cygwin/flock.cc | 7 ++++--- winsup/cygwin/release/3.5.5 | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/winsup/cygwin/flock.cc b/winsup/cygwin/flock.cc index 0f1efa01d4..5550b3a5ba 100644 --- a/winsup/cygwin/flock.cc +++ b/winsup/cygwin/flock.cc @@ -1454,13 +1454,14 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) /* * Add the new lock before overlap. */ - if (needtolink) { + if (needtolink) + { *prev = lock; lock->lf_next = overlap; - } + lock->create_lock_obj (); + } overlap->lf_start = lock->lf_end + 1; lf_wakelock (overlap, fhdl); - lock->create_lock_obj (); overlap->create_lock_obj (); break; } diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index bcc2c661b7..ca96edf043 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -12,3 +12,7 @@ Fixes: Addresses: https://sourceware.org/pipermail/cygwin/2024-September/256468.html - Fix timer_delete() return value which always indicated failure. + +- Fix lockf() error which occurs when adding a new lock over multiple + locks. + Addresses: https://cygwin.com/pipermail/cygwin/2024-October/256528.html From f86a181127d96f7dfcf457609cbec998631a837d Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Sun, 20 Oct 2024 01:54:00 +0900 Subject: [PATCH 012/116] Cygwin: lockf: Make lockf() return ENOLCK when too many locks Previously, lockf() printed a warning message when the number of locks per file exceeds the limit (MAX_LOCKF_CNT). This patch makes lockf() return ENOLCK in that case rather than printing the warning message. Addresses: https://cygwin.com/pipermail/cygwin/2024-October/256528.html Fixes: 31390e4ca643 ("(inode_t::get_all_locks_list): Use pre-allocated buffer in i_all_lf instead of allocating every lock. Return pointer to start of linked list of locks.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano --- winsup/cygwin/flock.cc | 82 +++++++++++++++++++++++++++++++++---- winsup/cygwin/release/3.5.5 | 4 ++ 2 files changed, 78 insertions(+), 8 deletions(-) diff --git a/winsup/cygwin/flock.cc b/winsup/cygwin/flock.cc index 5550b3a5ba..3821bddd67 100644 --- a/winsup/cygwin/flock.cc +++ b/winsup/cygwin/flock.cc @@ -297,6 +297,7 @@ class inode_t HANDLE i_dir; HANDLE i_mtx; uint32_t i_cnt; /* # of threads referencing this instance. */ + uint32_t i_lock_cnt; /* # of locks for this file */ public: inode_t (dev_t dev, ino_t ino); @@ -321,6 +322,8 @@ class inode_t void unlock_and_remove_if_unused (); lockf_t *get_all_locks_list (); + uint32_t get_lock_count () /* needs get_all_locks_list() */ + { return i_lock_cnt; } bool del_my_locks (long long id, HANDLE fhdl); }; @@ -503,7 +506,8 @@ inode_t::get (dev_t dev, ino_t ino, bool create_if_missing, bool lock) } inode_t::inode_t (dev_t dev, ino_t ino) -: i_lockf (NULL), i_all_lf (NULL), i_dev (dev), i_ino (ino), i_cnt (0L) +: i_lockf (NULL), i_all_lf (NULL), i_dev (dev), i_ino (ino), i_cnt (0L), + i_lock_cnt (0) { HANDLE parent_dir; WCHAR name[48]; @@ -610,17 +614,16 @@ inode_t::get_all_locks_list () dbi->ObjectName.Buffer[LOCK_OBJ_NAME_LEN] = L'\0'; if (!newlock.from_obj_name (this, &i_all_lf, dbi->ObjectName.Buffer)) continue; - if (lock - i_all_lf >= MAX_LOCKF_CNT) - { - system_printf ("Warning, can't handle more than %d locks per file.", - MAX_LOCKF_CNT); - break; - } + /* This should not be happen. The number of locks is limitted + in lf_setlock() and lf_clearlock() so that it does not + exceed MAX_LOCKF_CNT. */ + assert (lock - i_all_lf < MAX_LOCKF_CNT); if (lock > i_all_lf) lock[-1].lf_next = lock; new (lock++) lockf_t (newlock); } } + i_lock_cnt = lock - i_all_lf; /* If no lock has been found, return NULL. */ if (lock == i_all_lf) return NULL; @@ -1190,6 +1193,12 @@ fhandler_base::lock (int a_op, struct flock *fl) return -1; } +/* The total number of locks shall not exceed MAX_LOCKF_CNT. + If once it exceeds, lf_fildoverlap() cannot work correctly. + Therefore, lf_setlock() and lf_clearlock() control the + total number of locks not to exceed MAX_LOCKF_CNT. When + they detect that the operation will cause excess, they + return ENOCLK. */ /* * Set a byte-range lock. */ @@ -1346,14 +1355,31 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) * * Handle any locks that overlap. */ + node->get_all_locks_list (); /* Update lock count */ + uint32_t lock_cnt = node->get_lock_count (); + /* lf_clearlock() sometimes increases the number of locks. Without + this room, the unlocking will never succeed in some situation. */ + const uint32_t room_for_clearlock = 2; + const int incr[] = {1, 1, 2, 2, 3, 2}; + int decr = 0; + prev = head; block = *head; needtolink = 1; for (;;) { ovcase = lf_findoverlap (block, lock, SELF, &prev, &overlap); + /* Estimate the maximum increase in number of the locks that + can occur here. If this possibly exceeds the MAX_LOCKF_CNT, + return ENOLCK. */ if (ovcase) - block = overlap->lf_next; + { + block = overlap->lf_next; + HANDLE ov_obj = overlap->lf_obj; + decr = (ov_obj && get_obj_handle_count (ov_obj) == 1) ? 1 : 0; + } + if (needtolink) + lock_cnt += incr[ovcase] - decr; /* * Six cases: * 0) no overlap @@ -1368,6 +1394,8 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) case 0: /* no overlap */ if (needtolink) { + if (lock_cnt > MAX_LOCKF_CNT - room_for_clearlock) + return ENOLCK; *prev = lock; lock->lf_next = overlap; lock->create_lock_obj (); @@ -1380,6 +1408,8 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) * able to acquire it. * Cygwin: Always wake lock. */ + if (lock_cnt > MAX_LOCKF_CNT - room_for_clearlock) + return ENOLCK; lf_wakelock (overlap, fhdl); overlap->lf_type = lock->lf_type; overlap->create_lock_obj (); @@ -1397,6 +1427,11 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) *clean = lock; break; } + if (overlap->lf_start < lock->lf_start + && overlap->lf_end > lock->lf_end) + lock_cnt++; + if (lock_cnt > MAX_LOCKF_CNT - room_for_clearlock) + return ENOLCK; if (overlap->lf_start == lock->lf_start) { *prev = lock; @@ -1413,6 +1448,8 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) break; case 3: /* lock contains overlap */ + if (needtolink && lock_cnt > MAX_LOCKF_CNT - room_for_clearlock) + return ENOLCK; /* * If downgrading lock, others may be able to * acquire it, otherwise take the list. @@ -1440,6 +1477,8 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) /* * Add lock after overlap on the list. */ + if (lock_cnt > MAX_LOCKF_CNT - room_for_clearlock) + return ENOLCK; lock->lf_next = overlap->lf_next; overlap->lf_next = lock; overlap->lf_end = lock->lf_start - 1; @@ -1456,6 +1495,8 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) */ if (needtolink) { + if (lock_cnt > MAX_LOCKF_CNT - room_for_clearlock) + return ENOLCK; *prev = lock; lock->lf_next = overlap; lock->create_lock_obj (); @@ -1483,12 +1524,35 @@ lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl) lockf_t *lf = *head; lockf_t *overlap, **prev; int ovcase; + inode_t *node = lf->lf_inode; + tmp_pathbuf tp; + node->i_all_lf = (lockf_t *) tp.w_get (); + node->get_all_locks_list (); /* Update lock count */ + uint32_t lock_cnt = node->get_lock_count (); + bool first_loop = true; if (lf == NOLOCKF) return 0; prev = head; while ((ovcase = lf_findoverlap (lf, unlock, SELF, &prev, &overlap))) { + /* Estimate the maximum increase in number of the locks that + can occur here. If this possibly exceeds the MAX_LOCKF_CNT, + return ENOLCK. */ + HANDLE ov_obj = overlap->lf_obj; + if (first_loop) + { + const int incr[] = {0, 0, 1, 1, 2, 1}; + int decr = (ov_obj && get_obj_handle_count (ov_obj) == 1) ? 1 : 0; + lock_cnt += incr[ovcase] - decr; + if (ovcase == 2 + && overlap->lf_start < unlock->lf_start + && overlap->lf_end > unlock->lf_end) + lock_cnt++; + if (lock_cnt > MAX_LOCKF_CNT) + return ENOLCK; + } + /* * Wakeup the list of locks to be retried. */ @@ -1521,6 +1585,7 @@ lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl) lf = overlap->lf_next; overlap->lf_next = *clean; *clean = overlap; + first_loop = false; continue; case 4: /* overlap starts before lock */ @@ -1528,6 +1593,7 @@ lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl) prev = &overlap->lf_next; lf = overlap->lf_next; overlap->create_lock_obj (); + first_loop = false; continue; case 5: /* overlap ends after lock */ diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index ca96edf043..2dba4aa8f2 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -16,3 +16,7 @@ Fixes: - Fix lockf() error which occurs when adding a new lock over multiple locks. Addresses: https://cygwin.com/pipermail/cygwin/2024-October/256528.html + +- Make lockf() return ENOLCK when the number of locks exceeds + MAX_LOCKF_CNT rather than printing a warning message. + Addresses: https://cygwin.com/pipermail/cygwin/2024-October/256528.html From d70081274477a004de2b2aefcc936876b02b161a Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Thu, 31 Oct 2024 11:11:33 +0900 Subject: [PATCH 013/116] Cygwin: console: Inherit pcon hand over from parent pty There was a long-standing issue that pseudo console ownership could not hand over from the process whose ctty is /dev/cons* rather than /dev/pty*. This problem happens when a cygwin app starts non-cygwin app in a pty, then the non-cygwin app starts multiple cygwin apps, and the non-cygwin app ends before the second cygwin apps end. In this case, the stub process of the non-cygwin app hands over the ownership of pcon to one of the second cygwin apps, however, this app does not hand over the ownership of pcon to another second cygwin app. This is due to the fact that the hand-over feature is implemented only in fhandler_pty_slave but not in fhandler_console. With this patch, the second cygwin apps check if their console device is inside a pseudo console, and if so, it tries to hand over the ownership of the pseudo console to anther process that is attached to the same pseudo console. Addresses: https://cygwin.com/pipermail/cygwin/2024-February/255388.html Fixes: 253352e796ff ("Cygwin: pty: Allow multiple apps to enable pseudo console simultaneously.") Reported-by: lmari Lauhakangas , Hossein Nourikhah Signed-off-by: Takashi Yano --- winsup/cygwin/fhandler/console.cc | 64 ++++++++++++++++++++++++- winsup/cygwin/fhandler/pty.cc | 13 ++++- winsup/cygwin/fhandler/termios.cc | 6 +++ winsup/cygwin/local_includes/fhandler.h | 4 ++ winsup/cygwin/local_includes/tty.h | 1 + winsup/cygwin/release/3.5.5 | 4 ++ winsup/cygwin/spawn.cc | 1 + 7 files changed, 90 insertions(+), 3 deletions(-) diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc index dc43cd9f59..9cdc13dd23 100644 --- a/winsup/cygwin/fhandler/console.cc +++ b/winsup/cygwin/fhandler/console.cc @@ -60,6 +60,10 @@ const unsigned fhandler_console::MAX_WRITE_CHARS = 16384; fhandler_console::console_state NO_COPY *fhandler_console::shared_console_info[MAX_CONS_DEV + 1]; +static bool NO_COPY inside_pcon_checked = false; +static bool NO_COPY inside_pcon = false; +static int NO_COPY parent_pty; + bool NO_COPY fhandler_console::invisible_console; /* con_ra is shared in the same process. @@ -1894,12 +1898,69 @@ fhandler_console::open (int flags, mode_t) return 1; } +void +fhandler_console::setup_pcon_hand_over () +{ + /* Prepare for pcon hand over */ + if (!inside_pcon_checked) + for (int i = 0; i < NTTYS; i++) + { + if (!cygwin_shared->tty[i]->pcon_activated) + continue; + DWORD owner = cygwin_shared->tty[i]->nat_pipe_owner_pid; + if (fhandler_pty_common::get_console_process_id + (owner, true, false, false, false)) + { + inside_pcon = true; + atexit (fhandler_console::pcon_hand_over_proc); + parent_pty = i; + break; + } + } + inside_pcon_checked = true; +} + +void +fhandler_console::pcon_hand_over_proc (void) +{ + if (!inside_pcon) + return; + tty *ttyp = cygwin_shared->tty[parent_pty]; + char buf[MAX_PATH]; + shared_name (buf, PIPE_SW_MUTEX, parent_pty); + HANDLE mtx = OpenMutex (MAXIMUM_ALLOWED, FALSE, buf); + WaitForSingleObject (mtx, INFINITE); + ReleaseMutex (mtx); + DWORD res = WaitForSingleObject (mtx, INFINITE); + if (res == WAIT_OBJECT_0 || res == WAIT_ABANDONED) + { + DWORD owner = ttyp->nat_pipe_owner_pid; + if (owner == GetCurrentProcessId () + || owner == (myself->exec_dwProcessId ?: myself->dwProcessId)) + fhandler_pty_slave::close_pseudoconsole (ttyp, 0); + } + else + system_printf("Acquiring pcon_ho_mutex failed."); + /* Do not release the mutex. + Hold onto the mutex until this process completes. */ +} + bool fhandler_console::open_setup (int flags) { set_flags ((flags & ~O_TEXT) | O_BINARY); if (myself->set_ctty (this, flags) && !myself->cygstarted) - init_console_handler (true); + { + init_console_handler (true); + setup_pcon_hand_over (); + + /* Initialize handle_set */ + handle_set.input_handle = get_handle (); + handle_set.output_handle = get_output_handle (); + handle_set.input_mutex = input_mutex; + handle_set.output_mutex = output_mutex; + handle_set.unit = unit; + } return fhandler_base::open_setup (flags); } @@ -4327,6 +4388,7 @@ fhandler_console::fixup_after_fork_exec (bool execing) cygheap->ctty = NULL; return; } + setup_pcon_hand_over (); if (!execing) return; diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc index fa6bf10961..c40adc2895 100644 --- a/winsup/cygwin/fhandler/pty.cc +++ b/winsup/cygwin/fhandler/pty.cc @@ -102,6 +102,8 @@ fhandler_pty_common::get_console_process_id (DWORD pid, bool match, for (int i = (int) num - 1; i >= 0; i--) if ((match && list[i] == pid) || (!match && list[i] != pid)) { + if (!process_alive (list[i])) + continue; if (!cygwin) { res_pri = list[i]; @@ -117,7 +119,7 @@ fhandler_pty_common::get_console_process_id (DWORD pid, bool match, res_pri = stub_only ? p->exec_dwProcessId : list[i]; break; } - if (!p && !res && process_alive (list[i]) && stub_only) + if (!p && !res && stub_only) res = list[i]; if (!!p && !res && !stub_only) res = list[i]; @@ -1134,6 +1136,8 @@ process_alive (DWORD pid) inline static bool nat_pipe_owner_self (DWORD pid) { + if (pid == GetCurrentProcessId ()) + return true; return (pid == (myself->exec_dwProcessId ?: myself->dwProcessId)); } @@ -3541,11 +3545,16 @@ fhandler_pty_slave::get_winpid_to_hand_over (tty *ttyp, { /* Search another native process which attaches to the same console */ DWORD current_pid = myself->exec_dwProcessId ?: myself->dwProcessId; + if (ttyp->nat_pipe_owner_pid == GetCurrentProcessId ()) + current_pid = GetCurrentProcessId (); switch_to = get_console_process_id (current_pid, false, true, true, true); if (!switch_to) switch_to = get_console_process_id (current_pid, false, true, false, true); + if (!switch_to) + switch_to = get_console_process_id (current_pid, + false, false, false, false); } return switch_to; } @@ -3573,13 +3582,13 @@ fhandler_pty_slave::hand_over_only (tty *ttyp, DWORD force_switch_to) void fhandler_pty_slave::close_pseudoconsole (tty *ttyp, DWORD force_switch_to) { - DWORD switch_to = get_winpid_to_hand_over (ttyp, force_switch_to); acquire_attach_mutex (mutex_timeout); ttyp->previous_code_page = GetConsoleCP (); ttyp->previous_output_code_page = GetConsoleOutputCP (); release_attach_mutex (); if (nat_pipe_owner_self (ttyp->nat_pipe_owner_pid)) { /* I am owner of the nat pipe. */ + DWORD switch_to = get_winpid_to_hand_over (ttyp, force_switch_to); if (switch_to) { /* Change pseudo console owner to another process (switch_to). */ diff --git a/winsup/cygwin/fhandler/termios.cc b/winsup/cygwin/fhandler/termios.cc index d106955dcc..2acb0e01fa 100644 --- a/winsup/cygwin/fhandler/termios.cc +++ b/winsup/cygwin/fhandler/termios.cc @@ -827,3 +827,9 @@ fhandler_termios::spawn_worker::close_handle_set () if (cons_need_cleanup) fhandler_console::close_handle_set (&cons_handle_set); } + +void +fhandler_termios::atexit_func () +{ + fhandler_console::pcon_hand_over_proc (); +} diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h index 000004479b..b7b402ff61 100644 --- a/winsup/cygwin/local_includes/fhandler.h +++ b/winsup/cygwin/local_includes/fhandler.h @@ -2022,6 +2022,7 @@ class fhandler_termios: public fhandler_base virtual void setpgid_aux (pid_t pid) {} virtual bool need_console_handler () { return false; } virtual bool need_send_ctrl_c_event () { return true; } + static void atexit_func (); struct ptys_handle_set_t { @@ -2383,6 +2384,9 @@ class fhandler_console: public fhandler_termios console_unit (int, HANDLE *input_mutex = NULL); }; + void setup_pcon_hand_over (); + static void pcon_hand_over_proc (); + friend tty_min * tty_list::get_cttyp (); }; diff --git a/winsup/cygwin/local_includes/tty.h b/winsup/cygwin/local_includes/tty.h index 53fa26b449..2a047d73f9 100644 --- a/winsup/cygwin/local_includes/tty.h +++ b/winsup/cygwin/local_includes/tty.h @@ -178,6 +178,7 @@ class tty: public tty_min friend class fhandler_pty_master; friend class fhandler_pty_slave; friend class tty_min; + friend class fhandler_console; }; class tty_list diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index 2dba4aa8f2..cbaa172748 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -20,3 +20,7 @@ Fixes: - Make lockf() return ENOLCK when the number of locks exceeds MAX_LOCKF_CNT rather than printing a warning message. Addresses: https://cygwin.com/pipermail/cygwin/2024-October/256528.html + +- Make console inherit hand over of pseudo console ownership from + parent pty. + Addresses: https://cygwin.com/pipermail/cygwin/2024-February/255388.html diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index d01f678c3b..f5a4b91d76 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -888,6 +888,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, ctrl_c_handler(). This insures that setting sigExeced on Ctrl-C key has been completed. */ init_console_handler (false); + fhandler_termios::atexit_func (); myself.exit (EXITCODE_NOSET); break; case _P_WAIT: From 3d364b98c0c31c72ec2df382af2631ca414e4ff8 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Thu, 31 Oct 2024 11:52:26 +0100 Subject: [PATCH 014/116] Cygwin: pipe: fix shift value The expression computing the next-less-power of 2 for the next write when the pipe buffer is getting filled up allows negative shift values. This works on Intel CPUs because the shift expression only evaluates the 5 LSBs, but it's undefined behaviour per the C standard. Use the correct expression to get a positive shift value. Fixes: 170e6badb621 ("Cygwin: pipe: improve writing when pipe buffer is almost full") Reported-by: Takashi Yano Signed-off-by: Corinna Vinschen --- winsup/cygwin/fhandler/pipe.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/fhandler/pipe.cc b/winsup/cygwin/fhandler/pipe.cc index 3b78cc183e..6a1ef03b69 100644 --- a/winsup/cygwin/fhandler/pipe.cc +++ b/winsup/cygwin/fhandler/pipe.cc @@ -580,7 +580,7 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len) else if (avail >= PIPE_BUF) len1 = avail & ~(PIPE_BUF - 1); else - len1 = 1 << (31 - __builtin_clzl (avail)); + len1 = 1 << (63 - __builtin_clzl (avail)); short_write_once = true; } if (isclosed ()) /* A signal handler might have closed the fd. */ From 2962922d031ce2e3b32666b434eb9ce75192739c Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Fri, 1 Nov 2024 04:42:18 +0900 Subject: [PATCH 015/116] Add recent pipe change to release note --- winsup/cygwin/release/3.5.5 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index cbaa172748..dbd6b026b4 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -24,3 +24,6 @@ Fixes: - Make console inherit hand over of pseudo console ownership from parent pty. Addresses: https://cygwin.com/pipermail/cygwin/2024-February/255388.html + +- Restore pipe blocking mode for non-cygwin apps. + Addresses: https://github.com/git-for-windows/git/issues/5115 From ea01b87f0f43068fd69658725268ec403ad3b5e9 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Thu, 31 Oct 2024 15:47:35 +0900 Subject: [PATCH 016/116] Cygwin: cygfe: Fix a bug that signal handler destroys fpu states Previously, sigfe had a long-standing problem that the signal handler destroys fpu states. This is caused by fninit instruction in sigdelayed. With this patch, instead of fnstcw/fldcw and fninit, fnstenv/fldenv are used to maintain fpu states. Addresses: https://cygwin.com/pipermail/cygwin/2024-October/256503.html Fixes: ed89fbc3ff11 ("* gendef (sigdelayed (x86_64)): Save and restore FPU control word.") Reported-by: Christian Franke Reviewed-by: Signed-off-by: Takashi Yano --- winsup/cygwin/release/3.5.5 | 3 +++ winsup/cygwin/scripts/gendef | 15 +++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index dbd6b026b4..9cc51dc2e6 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -27,3 +27,6 @@ Fixes: - Restore pipe blocking mode for non-cygwin apps. Addresses: https://github.com/git-for-windows/git/issues/5115 + +- Fix a problem that signal handler destroys the FPU context. + Addresses: https://cygwin.com/pipermail/cygwin/2024-October/256503.html diff --git a/winsup/cygwin/scripts/gendef b/winsup/cygwin/scripts/gendef index 3b1f8b9dae..c2ad5c75e3 100755 --- a/winsup/cygwin/scripts/gendef +++ b/winsup/cygwin/scripts/gendef @@ -213,10 +213,10 @@ sigdelayed: .seh_pushreg %rbx pushq %rax .seh_pushreg %rax - subq \$0x128,%rsp - .seh_stackalloc 0x128 - stmxcsr 0x124(%rsp) - fnstcw 0x120(%rsp) + subq \$0x148,%rsp + .seh_stackalloc 0x148 + stmxcsr 0x13c(%rsp) + fnstenv 0x120(%rsp) movdqa %xmm15,0x110(%rsp) movdqa %xmm14,0x100(%rsp) movdqa %xmm13,0xf0(%rsp) @@ -275,10 +275,9 @@ sigdelayed: movdqa 0xf0(%rsp),%xmm13 movdqa 0x100(%rsp),%xmm14 movdqa 0x110(%rsp),%xmm15 - fninit - fldcw 0x120(%rsp) - ldmxcsr 0x124(%rsp) - addq \$0x128,%rsp + fldenv 0x120(%rsp) + ldmxcsr 0x13c(%rsp) + addq \$0x148,%rsp popq %rax popq %rbx popq %rcx From 73168846ea25b6f64cab9fa6c85b13bfeac3b3df Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Tue, 5 Nov 2024 20:20:21 +0900 Subject: [PATCH 017/116] Cygwin: console: Fix open() failure when the console owner calls exec(). Currently, open() tries to attach to the console which is owned by the console owner process. However, when the owner process calls exec(), AttachConsole() to dwProcessId may sometimes fail due to unlucky timing. With this patch, open() tries to attach also to exec_dwProcessId if attaching to dwProcessId fails. That is, open() tries to attach to both the stub process and target process to prevent the above situation. Fixes: 3721a756b0d8 ("Cygwin: console: Make the console accessible from other terminals.") Signed-off-by: Takashi Yano --- winsup/cygwin/fhandler/console.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc index 9cdc13dd23..ac47c83747 100644 --- a/winsup/cygwin/fhandler/console.cc +++ b/winsup/cygwin/fhandler/console.cc @@ -84,6 +84,10 @@ fhandler_console::attach_console (pid_t owner, bool *err) DWORD attached = fhandler_pty_common::get_console_process_id (p->dwProcessId, true, false, false); + if (!attached) + attached = + fhandler_pty_common::get_console_process_id (p->exec_dwProcessId, + true, false, false); if (!attached) { resume_pid = @@ -91,6 +95,8 @@ fhandler_console::attach_console (pid_t owner, bool *err) false, false, false); FreeConsole (); BOOL r = AttachConsole (p->dwProcessId); + if (!r) + r = AttachConsole (p->exec_dwProcessId); if (!r) { if (resume_pid) From f307544150ddf3de78a7edb3f04a983c3efc6c19 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Wed, 6 Nov 2024 10:19:59 +0900 Subject: [PATCH 018/116] Cygwin: console: Re-fix open() failure on exec() by console owner Previous fix (commit df0953aa298c) fixes only a part of the problem. Since exec() overrides the cygwin pid of the caller process, it makes console owner handling complex. This patch makes console use Windows pid as the owner pid (con.owner) instead of cygwin pid to make the handling simpler. Fixes: df0953aa298c ("Cygwin: console: Fix open() failure when the console owner calls exec().") Signed-off-by: Takashi Yano (cherry picked from commit 90ddab98780da0e888ff09987d4651107c0f48d6) --- winsup/cygwin/fhandler/console.cc | 86 ++++++++++--------------- winsup/cygwin/fhandler/pty.cc | 73 --------------------- winsup/cygwin/fhandler/termios.cc | 72 +++++++++++++++++++++ winsup/cygwin/local_includes/fhandler.h | 19 +++--- 4 files changed, 117 insertions(+), 133 deletions(-) diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc index ac47c83747..7ac9265547 100644 --- a/winsup/cygwin/fhandler/console.cc +++ b/winsup/cygwin/fhandler/console.cc @@ -75,43 +75,33 @@ static struct fhandler_base::rabuf_t con_ra; static wchar_t last_char; DWORD -fhandler_console::attach_console (pid_t owner, bool *err) +fhandler_console::attach_console (DWORD owner, bool *err) { DWORD resume_pid = (DWORD) -1; - pinfo p (owner); - if (p) + if (!process_alive (owner)) + return resume_pid; + DWORD attached = + get_console_process_id (owner, true, false, false); + if (!attached) { - DWORD attached = - fhandler_pty_common::get_console_process_id (p->dwProcessId, - true, false, false); - if (!attached) - attached = - fhandler_pty_common::get_console_process_id (p->exec_dwProcessId, - true, false, false); - if (!attached) + resume_pid = + get_console_process_id (myself->dwProcessId, false, false, false); + FreeConsole (); + BOOL r = AttachConsole (owner); + if (!r) { - resume_pid = - fhandler_pty_common::get_console_process_id (myself->dwProcessId, - false, false, false); - FreeConsole (); - BOOL r = AttachConsole (p->dwProcessId); - if (!r) - r = AttachConsole (p->exec_dwProcessId); - if (!r) - { - if (resume_pid) - AttachConsole (resume_pid); - if (err) - *err = true; - return (DWORD) -1; - } + if (resume_pid) + AttachConsole (resume_pid); + if (err) + *err = true; + return (DWORD) -1; } } return resume_pid; } void -fhandler_console::detach_console (DWORD resume_pid, pid_t owner) +fhandler_console::detach_console (DWORD resume_pid, DWORD owner) { if (resume_pid == (DWORD) -1) return; @@ -120,11 +110,11 @@ fhandler_console::detach_console (DWORD resume_pid, pid_t owner) FreeConsole (); AttachConsole (resume_pid); } - else if (myself->pid != owner) + else if (myself->dwProcessId != owner) FreeConsole (); } -pid_t +DWORD fhandler_console::get_owner () { return con.owner; @@ -143,14 +133,14 @@ static class write_pending_buffer { empty (); } - inline void put (HANDLE output_handle, pid_t owner, char x) + inline void put (HANDLE output_handle, DWORD owner, char x) { if (ixput == WPBUF_LEN) send (output_handle, owner); buf[ixput++] = x; } inline void empty () { ixput = 0u; } - inline void send (HANDLE output_handle, pid_t owner) + inline void send (HANDLE output_handle, DWORD owner) { if (!output_handle) { @@ -405,7 +395,7 @@ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp) } }; termios &ti = ttyp->ti; - while (con.owner == myself->pid) + while (con.owner == myself->dwProcessId) { DWORD total_read, n, i; @@ -719,7 +709,7 @@ fhandler_console::set_unit () unit = device::minor (cs->tty_min_state.ntty); shared_console_info[unit] = cs; if (created) - con.owner = myself->pid; + con.owner = myself->dwProcessId; } } } @@ -927,10 +917,10 @@ fhandler_console::cleanup_for_non_cygwin_app (handle_set_t *p) /* conmode can be tty::restore when non-cygwin app is exec'ed from login shell. */ tty::cons_mode conmode = - (con.owner == myself->pid) ? tty::restore : tty::cygwin; + (con.owner == myself->dwProcessId) ? tty::restore : tty::cygwin; set_output_mode (conmode, ti, p); set_input_mode (conmode, ti, p); - set_disable_master_thread (con.owner == myself->pid); + set_disable_master_thread (con.owner == myself->dwProcessId); } /* Return the tty structure associated with a given tty number. If the @@ -1043,7 +1033,7 @@ fhandler_console::set_cursor_maybe () /* Workaround for a bug of windows xterm compatible mode. */ /* The horizontal tab positions are broken after resize. */ void -fhandler_console::fix_tab_position (HANDLE h, pid_t owner) +fhandler_console::fix_tab_position (HANDLE h, DWORD owner) { /* Re-setting ENABLE_VIRTUAL_TERMINAL_PROCESSING fixes the tab position. */ @@ -1783,13 +1773,8 @@ fhandler_console::open (int flags, mode_t) setup_io_mutex (); acquire_output_mutex (mutex_timeout); - do - { - pinfo p (con.owner); - if (!p) - con.owner = myself->pid; - } - while (false); + if (!process_alive (con.owner)) + con.owner = myself->dwProcessId; /* Open the input handle as handle_ */ bool err = false; @@ -1853,7 +1838,7 @@ fhandler_console::open (int flags, mode_t) set_open_status (); - if (myself->pid == con.owner && wincap.has_con_24bit_colors ()) + if (myself->dwProcessId == con.owner && wincap.has_con_24bit_colors ()) { bool is_legacy = false; DWORD dwMode; @@ -1884,7 +1869,7 @@ fhandler_console::open (int flags, mode_t) debug_printf ("opened conin$ %p, conout$ %p", get_handle (), get_output_handle ()); - if (myself->pid == con.owner) + if (myself->dwProcessId == con.owner) { if (GetModuleHandle ("ConEmuHk64.dll")) hook_conemu_cygwin_connector (); @@ -1914,8 +1899,7 @@ fhandler_console::setup_pcon_hand_over () if (!cygwin_shared->tty[i]->pcon_activated) continue; DWORD owner = cygwin_shared->tty[i]->nat_pipe_owner_pid; - if (fhandler_pty_common::get_console_process_id - (owner, true, false, false, false)) + if (get_console_process_id (owner, true, false, false, false)) { inside_pcon = true; atexit (fhandler_console::pcon_hand_over_proc); @@ -2001,7 +1985,7 @@ fhandler_console::close () &obi, sizeof obi, NULL); if ((NT_SUCCESS (status) && obi.HandleCount == 1 && (dev_t) myself->ctty == get_device ()) - || myself->pid == con.owner) + || myself->dwProcessId == con.owner) { /* Cleaning-up console mode for cygwin apps. */ set_output_mode (tty::restore, &get_ttyp ()->ti, &handle_set); @@ -2010,7 +1994,7 @@ fhandler_console::close () } } - if (shared_console_info[unit] && con.owner == myself->pid) + if (shared_console_info[unit] && con.owner == myself->dwProcessId) { if (master_thread_started) { @@ -2019,7 +2003,7 @@ fhandler_console::close () thread_sync_event = OpenEvent (MAXIMUM_ALLOWED, FALSE, name); if (thread_sync_event) { - con.owner = MAX_PID + 1; + con.owner = (DWORD) -1; WaitForSingleObject (thread_sync_event, INFINITE); CloseHandle (thread_sync_event); } @@ -3508,7 +3492,7 @@ enum_proc (const LOGFONTW *lf, const TEXTMETRICW *tm, } static void -check_font (HANDLE hdl, pid_t owner) +check_font (HANDLE hdl, DWORD owner) { CONSOLE_FONT_INFOEX cfi; LOGFONTW lf; diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc index c40adc2895..4f0f718127 100644 --- a/winsup/cygwin/fhandler/pty.cc +++ b/winsup/cygwin/fhandler/pty.cc @@ -74,60 +74,6 @@ void release_attach_mutex (void) ReleaseMutex (attach_mutex); } -inline static bool process_alive (DWORD pid); - -/* This functions looks for a process which attached to the same console - with current process and is matched to given conditions: - match: If true, return given pid if the process pid attaches to the - same console, otherwise, return 0. If false, return pid except - for given pid. - cygwin: return only process's pid which has cygwin pid. - stub_only: return only stub process's pid of non-cygwin process. */ -DWORD -fhandler_pty_common::get_console_process_id (DWORD pid, bool match, - bool cygwin, bool stub_only, - bool nat) -{ - tmp_pathbuf tp; - DWORD *list = (DWORD *) tp.c_get (); - const DWORD buf_size = NT_MAX_PATH / sizeof (DWORD); - - DWORD num = GetConsoleProcessList (list, buf_size); - if (num == 0 || num > buf_size) - return 0; - - DWORD res_pri = 0, res = 0; - /* Last one is the oldest. */ - /* https://github.com/microsoft/terminal/issues/95 */ - for (int i = (int) num - 1; i >= 0; i--) - if ((match && list[i] == pid) || (!match && list[i] != pid)) - { - if (!process_alive (list[i])) - continue; - if (!cygwin) - { - res_pri = list[i]; - break; - } - else - { - pinfo p (cygwin_pid (list[i])); - if (nat && !!p && !ISSTATE(p, PID_NOTCYGWIN)) - continue; - if (!!p && p->exec_dwProcessId) - { - res_pri = stub_only ? p->exec_dwProcessId : list[i]; - break; - } - if (!p && !res && stub_only) - res = list[i]; - if (!!p && !res && !stub_only) - res = list[i]; - } - } - return res_pri ?: res; -} - static bool isHybrid; /* Set true if the active pipe is set to nat pipe owned by myself even though the current process is a cygwin process. */ @@ -1114,25 +1060,6 @@ fhandler_pty_slave::set_switch_to_nat_pipe (void) } } -inline static bool -process_alive (DWORD pid) -{ - /* This function is very similar to _pinfo::alive(), however, this - can be used for non-cygwin process which is started from non-cygwin - shell. In addition, this checks exit code as well. */ - if (pid == 0) - return false; - HANDLE h = OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); - if (h == NULL) - return false; - DWORD exit_code; - BOOL r = GetExitCodeProcess (h, &exit_code); - CloseHandle (h); - if (r && exit_code == STILL_ACTIVE) - return true; - return false; -} - inline static bool nat_pipe_owner_self (DWORD pid) { diff --git a/winsup/cygwin/fhandler/termios.cc b/winsup/cygwin/fhandler/termios.cc index 2acb0e01fa..585e6ac4ac 100644 --- a/winsup/cygwin/fhandler/termios.cc +++ b/winsup/cygwin/fhandler/termios.cc @@ -20,6 +20,7 @@ details. */ #include "cygheap.h" #include "child_info.h" #include "ntdll.h" +#include "tls_pbuf.h" /* Wait time for some treminal mutexes. This is set to 0 when the process calls CreateProcess() with DEBUG_PROCESS flag, because @@ -833,3 +834,74 @@ fhandler_termios::atexit_func () { fhandler_console::pcon_hand_over_proc (); } + +bool +fhandler_termios::process_alive (DWORD pid) +{ + /* This function is very similar to _pinfo::alive(), however, this + can be used for non-cygwin process which is started from non-cygwin + shell. In addition, this checks exit code as well. */ + if (pid == 0) + return false; + HANDLE h = OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); + if (h == NULL) + return false; + DWORD exit_code; + BOOL r = GetExitCodeProcess (h, &exit_code); + CloseHandle (h); + if (r && exit_code == STILL_ACTIVE) + return true; + return false; +} + +/* This functions looks for a process which attached to the same console + with current process and is matched to given conditions: + match: If true, return given pid if the process pid attaches to the + same console, otherwise, return 0. If false, return pid except + for given pid. + cygwin: return only process's pid which has cygwin pid. + stub_only: return only stub process's pid of non-cygwin process. */ +DWORD +fhandler_termios::get_console_process_id (DWORD pid, bool match, + bool cygwin, bool stub_only, + bool nat) +{ + tmp_pathbuf tp; + DWORD *list = (DWORD *) tp.c_get (); + const DWORD buf_size = NT_MAX_PATH / sizeof (DWORD); + + DWORD num = GetConsoleProcessList (list, buf_size); + if (num == 0 || num > buf_size) + return 0; + + DWORD res_pri = 0, res = 0; + /* Last one is the oldest. */ + /* https://github.com/microsoft/terminal/issues/95 */ + for (int i = (int) num - 1; i >= 0; i--) + if ((match && list[i] == pid) || (!match && list[i] != pid)) + { + if (!process_alive (list[i])) + continue; + if (!cygwin) + { + res_pri = list[i]; + break; + } + else + { + pinfo p (cygwin_pid (list[i])); + if (nat && !!p && !ISSTATE(p, PID_NOTCYGWIN)) + continue; + if (!!p && p->exec_dwProcessId) + { + res_pri = stub_only ? p->exec_dwProcessId : list[i]; + break; + } + if (!p && !res && stub_only) + res = list[i]; + if (!!p && !res && !stub_only) + res = list[i]; + } + } + return res_pri ?: res; +} diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h index b7b402ff61..88a6b7d47b 100644 --- a/winsup/cygwin/local_includes/fhandler.h +++ b/winsup/cygwin/local_includes/fhandler.h @@ -1970,6 +1970,11 @@ class fhandler_termios: public fhandler_base done_with_debugger /* The key was processed (CTRL_C_EVENT was sent) for inferior of GDB. */ }; + static bool process_alive (DWORD pid); + static DWORD get_console_process_id (DWORD pid, bool match, + bool cygwin = false, + bool stub_only = false, + bool nat = false); public: virtual pid_t tc_getpgid () { return 0; }; @@ -2093,7 +2098,7 @@ enum cltype class dev_console { - pid_t owner; + DWORD owner; bool is_legacy; bool orig_virtual_terminal_processing_mode; @@ -2243,7 +2248,7 @@ class fhandler_console: public fhandler_termios void set_cursor_maybe (); static bool create_invisible_console_workaround (bool force); static console_state *open_shared_console (HWND, HANDLE&, bool&); - static void fix_tab_position (HANDLE h, pid_t owner); + static void fix_tab_position (HANDLE h, DWORD owner); /* console mode calls */ const handle_set_t *get_handle_set (void) {return &handle_set;} @@ -2368,9 +2373,9 @@ class fhandler_console: public fhandler_termios static void set_console_mode_to_native (); bool need_console_handler (); static void set_disable_master_thread (bool x, fhandler_console *cons = NULL); - static DWORD attach_console (pid_t, bool *err = NULL); - static void detach_console (DWORD, pid_t); - pid_t get_owner (); + static DWORD attach_console (DWORD, bool *err = NULL); + static void detach_console (DWORD, DWORD); + DWORD get_owner (); void wpbuf_put (char c); void wpbuf_send (); int fstat (struct stat *buf); @@ -2434,10 +2439,6 @@ class fhandler_pty_common: public fhandler_termios } void resize_pseudo_console (struct winsize *); - static DWORD get_console_process_id (DWORD pid, bool match, - bool cygwin = false, - bool stub_only = false, - bool nat = false); bool to_be_read_from_nat_pipe (void); static DWORD attach_console_temporarily (DWORD target_pid); static void resume_from_temporarily_attach (DWORD resume_pid); From 92f4e103d187f0b5a27d1a93d2cc22a9909ece68 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Wed, 6 Nov 2024 22:43:13 +0900 Subject: [PATCH 019/116] Cygwin: console: Use GetCurrentProcessId() instead of myself->dwProcessId The commit 90ddab98780d uses myself->dwProcessId to get windows pid. However, it will be overridden in stub process if exec() is called. With this patch, GetCurrentProcessId() instead of myself->dwProcessId. Fixes: 90ddab98780d ("Cygwin: console: Re-fix open() failure on exec() by console owner") Signed-off-by: Takashi Yano (cherry picked from commit 8ee8b0c974d723d618182fbbdeb1e9186b69c6f3) --- winsup/cygwin/fhandler/console.cc | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc index 7ac9265547..4efba61e25 100644 --- a/winsup/cygwin/fhandler/console.cc +++ b/winsup/cygwin/fhandler/console.cc @@ -85,7 +85,7 @@ fhandler_console::attach_console (DWORD owner, bool *err) if (!attached) { resume_pid = - get_console_process_id (myself->dwProcessId, false, false, false); + get_console_process_id (GetCurrentProcessId (), false, false, false); FreeConsole (); BOOL r = AttachConsole (owner); if (!r) @@ -110,7 +110,7 @@ fhandler_console::detach_console (DWORD resume_pid, DWORD owner) FreeConsole (); AttachConsole (resume_pid); } - else if (myself->dwProcessId != owner) + else if (GetCurrentProcessId () != owner) FreeConsole (); } @@ -395,7 +395,7 @@ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp) } }; termios &ti = ttyp->ti; - while (con.owner == myself->dwProcessId) + while (con.owner == GetCurrentProcessId ()) { DWORD total_read, n, i; @@ -709,7 +709,7 @@ fhandler_console::set_unit () unit = device::minor (cs->tty_min_state.ntty); shared_console_info[unit] = cs; if (created) - con.owner = myself->dwProcessId; + con.owner = GetCurrentProcessId (); } } } @@ -917,10 +917,10 @@ fhandler_console::cleanup_for_non_cygwin_app (handle_set_t *p) /* conmode can be tty::restore when non-cygwin app is exec'ed from login shell. */ tty::cons_mode conmode = - (con.owner == myself->dwProcessId) ? tty::restore : tty::cygwin; + (con.owner == GetCurrentProcessId ()) ? tty::restore : tty::cygwin; set_output_mode (conmode, ti, p); set_input_mode (conmode, ti, p); - set_disable_master_thread (con.owner == myself->dwProcessId); + set_disable_master_thread (con.owner == GetCurrentProcessId ()); } /* Return the tty structure associated with a given tty number. If the @@ -1774,7 +1774,7 @@ fhandler_console::open (int flags, mode_t) acquire_output_mutex (mutex_timeout); if (!process_alive (con.owner)) - con.owner = myself->dwProcessId; + con.owner = GetCurrentProcessId (); /* Open the input handle as handle_ */ bool err = false; @@ -1838,7 +1838,7 @@ fhandler_console::open (int flags, mode_t) set_open_status (); - if (myself->dwProcessId == con.owner && wincap.has_con_24bit_colors ()) + if (GetCurrentProcessId () == con.owner && wincap.has_con_24bit_colors ()) { bool is_legacy = false; DWORD dwMode; @@ -1869,7 +1869,7 @@ fhandler_console::open (int flags, mode_t) debug_printf ("opened conin$ %p, conout$ %p", get_handle (), get_output_handle ()); - if (myself->dwProcessId == con.owner) + if (GetCurrentProcessId () == con.owner) { if (GetModuleHandle ("ConEmuHk64.dll")) hook_conemu_cygwin_connector (); @@ -1983,9 +1983,9 @@ fhandler_console::close () NTSTATUS status; status = NtQueryObject (get_handle (), ObjectBasicInformation, &obi, sizeof obi, NULL); - if ((NT_SUCCESS (status) && obi.HandleCount == 1 - && (dev_t) myself->ctty == get_device ()) - || myself->dwProcessId == con.owner) + if (NT_SUCCESS (status) + && obi.HandleCount <= (myself->cygstarted ? 2 : 3) + && (dev_t) myself->ctty == get_device ()) { /* Cleaning-up console mode for cygwin apps. */ set_output_mode (tty::restore, &get_ttyp ()->ti, &handle_set); @@ -1994,7 +1994,7 @@ fhandler_console::close () } } - if (shared_console_info[unit] && con.owner == myself->dwProcessId) + if (shared_console_info[unit] && con.owner == GetCurrentProcessId ()) { if (master_thread_started) { From 38ab2b77e325bf5c9d25cb832f8b80c58ff80299 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Fri, 8 Nov 2024 20:02:35 +0900 Subject: [PATCH 020/116] Cygwin: console: Fix clean up conditions in close() Previously, the condition to clean up input/output mode was based on wrong premise. This patch fixes that. Fixes: 8ee8b0c974d7 ("Cygwin: console: Use GetCurrentProcessId() instead of myself->dwProcessId") Signed-off-by: Takashi Yano (cherry picked from commit 30d266947842fec82cae9a190bc8b5bf2e108cd0) --- winsup/cygwin/fhandler/console.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc index 4efba61e25..2651e49a62 100644 --- a/winsup/cygwin/fhandler/console.cc +++ b/winsup/cygwin/fhandler/console.cc @@ -1976,7 +1976,8 @@ fhandler_console::close () acquire_output_mutex (mutex_timeout); - if (shared_console_info[unit]) + if (shared_console_info[unit] && !myself->cygstarted + && (dev_t) myself->ctty == get_device ()) { /* Restore console mode if this is the last closure. */ OBJECT_BASIC_INFORMATION obi; @@ -1984,8 +1985,7 @@ fhandler_console::close () status = NtQueryObject (get_handle (), ObjectBasicInformation, &obi, sizeof obi, NULL); if (NT_SUCCESS (status) - && obi.HandleCount <= (myself->cygstarted ? 2 : 3) - && (dev_t) myself->ctty == get_device ()) + && obi.HandleCount == (con.owner == GetCurrentProcessId () ? 2 : 3)) { /* Cleaning-up console mode for cygwin apps. */ set_output_mode (tty::restore, &get_ttyp ()->ti, &handle_set); From 9dad29c238bfce017f54915b90a1c2c4fcac9529 Mon Sep 17 00:00:00 2001 From: Shaobo Song Date: Sun, 10 Nov 2024 12:15:04 +0800 Subject: [PATCH 021/116] Cygwin: pthread: Correct pthread_cleanup macros to avoid potential syntax errors This commit revises `pthread_cleanup_push` and `pthread_cleanup_pop` macros to use a `do { ... } while(0)` wrapper, preventing syntax errors when used in certain contexts. The original code could fail when they are wrapped within a `do { ... } while(0)`, causing unintended behavior or compilation issues. Example of error: #include #define pthread_cleanup_push_wrapper(_fn, _arg) do { \ pthread_cleanup_push(_fn, _arg); \ } while (0) #define pthread_cleanup_pop_wrapper(_execute) do { \ pthread_cleanup_pop(_execute); \ } while (0) void cleanup_fn (void *arg) {} void *thread_func (void *arg) { pthread_cleanup_push_wrapper(cleanup_fn, NULL); pthread_cleanup_pop_wrapper(1); return NULL; } int main (int argc, char **argv) { pthread_t thread_id; pthread_create(&thread_id, NULL, thread_func, NULL); } This would fail due to unmatched braces in the macro expansion. The new structure ensures the macro expands correctly in all cases. Fixes: 007276b30e0a ("* cygwin.din: Add _pthread_cleanup_push and _pthread_cleanup_pop.") Signed-off-by: Shaobo Song --- winsup/cygwin/include/pthread.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/winsup/cygwin/include/pthread.h b/winsup/cygwin/include/pthread.h index 66d367d622..cf2fcb04b3 100644 --- a/winsup/cygwin/include/pthread.h +++ b/winsup/cygwin/include/pthread.h @@ -110,10 +110,13 @@ typedef struct _pthread_cleanup_handler void _pthread_cleanup_push (__pthread_cleanup_handler *handler); void _pthread_cleanup_pop (int execute); -#define pthread_cleanup_push(_fn, _arg) { __pthread_cleanup_handler __cleanup_handler = \ - { _fn, _arg, NULL }; \ - _pthread_cleanup_push( &__cleanup_handler ); -#define pthread_cleanup_pop(_execute) _pthread_cleanup_pop( _execute ); } +#define pthread_cleanup_push(_fn, _arg) \ + do { \ + __pthread_cleanup_handler __cleanup_handler = { _fn, _arg, NULL }; \ + _pthread_cleanup_push(&__cleanup_handler) +#define pthread_cleanup_pop(_execute) \ + _pthread_cleanup_pop(_execute); \ + } while (0) /* Condition variables */ int pthread_cond_broadcast (pthread_cond_t *); From b9060e06a6e4f52ad3c27488b32f7a825114e6b4 Mon Sep 17 00:00:00 2001 From: Mark Geisert Date: Mon, 11 Nov 2024 22:38:29 -0800 Subject: [PATCH 022/116] Cygwin: Change pthread_sigqueue() to accept thread id Change the first parameter of pthread_sigqueue() to be a thread id rather than a thread pointer. The change is to match the Linux implementation of this function. The user-visible function prototype is changed in include/pthread.h. The pthread_sigqueue() function is modified to work with a passed-in thread id rather than an indirect thread pointer as before. (It used to be "pthread_t *thread", i.e., class pthread **.) The release note for Cygwin 3.5.5 is updated. Reported-by: Christian Franke Addresses: https://cygwin.com/pipermail/cygwin/2024-September/256439.html Signed-off-by: Mark Geisert Fixes: 50350cafb375 ("* cygwin.din (pthread_sigqueue): Export.") (cherry picked from commit 1e8c92e21d386d2e4a29fa92e8258979ff19ae6b) --- winsup/cygwin/include/pthread.h | 2 +- winsup/cygwin/release/3.5.5 | 3 +++ winsup/cygwin/thread.cc | 8 ++++---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/winsup/cygwin/include/pthread.h b/winsup/cygwin/include/pthread.h index cf2fcb04b3..8e296303d7 100644 --- a/winsup/cygwin/include/pthread.h +++ b/winsup/cygwin/include/pthread.h @@ -247,7 +247,7 @@ int pthread_getattr_np (pthread_t, pthread_attr_t *); int pthread_getname_np (pthread_t, char *, size_t) __attribute__((__nonnull__(2))); int pthread_setaffinity_np (pthread_t, size_t, const cpu_set_t *); int pthread_setname_np (pthread_t, const char *) __attribute__((__nonnull__(2))); -int pthread_sigqueue (pthread_t *, int, const union sigval); +int pthread_sigqueue (pthread_t, int, const union sigval); int pthread_timedjoin_np (pthread_t, void **, const struct timespec *); int pthread_tryjoin_np (pthread_t, void **); #endif diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index 9cc51dc2e6..2ca4572db7 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -30,3 +30,6 @@ Fixes: - Fix a problem that signal handler destroys the FPU context. Addresses: https://cygwin.com/pipermail/cygwin/2024-October/256503.html + +- Fix type of pthread_sigqueue() first parameter to match Linux. + Addresses: https://cygwin.com/pipermail/cygwin/2024-September/256439.html diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index 0c6f570322..9ee96504b8 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -3301,13 +3301,13 @@ pthread_sigmask (int operation, const sigset_t *set, sigset_t *old_set) } int -pthread_sigqueue (pthread_t *thread, int sig, const union sigval value) +pthread_sigqueue (pthread_t thread, int sig, const union sigval value) { siginfo_t si = {0}; - if (!pthread::is_good_object (thread)) + if (!pthread::is_good_object (&thread)) return EINVAL; - if (!(*thread)->valid) + if (!thread->valid) return ESRCH; si.si_signo = sig; @@ -3315,7 +3315,7 @@ pthread_sigqueue (pthread_t *thread, int sig, const union sigval value) si.si_value = value; si.si_pid = myself->pid; si.si_uid = myself->uid; - return (int) sig_send (NULL, si, (*thread)->cygtls); + return (int) sig_send (NULL, si, thread->cygtls); } /* Cancelability */ From 22474a6e5d134407db3951e65c5b89a4bd700580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20=C3=9Cbelacker?= Date: Sat, 16 Nov 2024 18:09:50 +0100 Subject: [PATCH 023/116] Cygwin: check_dir_not_empty: Avoid leaving the allocated buffer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pointer pfni gets allocated the buffer at the begin, and is used in the NtQueryDirectoryFile call before the loops. In the loop the pointer pfni is also used as iterator. Therefore it holds no longer the initial buffer at the call to NtQueryDirectoryFile in the while conditition at the bottom. Fixes: 28fa2a72f8106 ("* syscalls.cc (check_dir_not_empty): Check surplus directory entries") Co-authored-by: Corinna Vinschen Signed-off-by: Bernhard Übelacker (cherry picked from commit dbb8069df56cb68ea1167b3bc0ceb66fa6c35d3f) --- winsup/cygwin/release/3.5.5 | 3 +++ winsup/cygwin/syscalls.cc | 10 ++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index 2ca4572db7..3088f8682b 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -33,3 +33,6 @@ Fixes: - Fix type of pthread_sigqueue() first parameter to match Linux. Addresses: https://cygwin.com/pipermail/cygwin/2024-September/256439.html + +- Fix potential stack corruption in rmdir() in a border case. + Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256774.html diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 9d88b60b0f..1d9308ef46 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -617,9 +617,10 @@ check_dir_not_empty (HANDLE dir, path_conv &pc) IO_STATUS_BLOCK io; const ULONG bufsiz = 3 * sizeof (FILE_NAMES_INFORMATION) + 3 * NAME_MAX * sizeof (WCHAR); - PFILE_NAMES_INFORMATION pfni = (PFILE_NAMES_INFORMATION) - alloca (bufsiz); - NTSTATUS status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, pfni, + PFILE_NAMES_INFORMATION pfni_buf = (PFILE_NAMES_INFORMATION) + alloca (bufsiz); + PFILE_NAMES_INFORMATION pfni; + NTSTATUS status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, pfni_buf, bufsiz, FileNamesInformation, FALSE, NULL, TRUE); if (!NT_SUCCESS (status)) @@ -631,6 +632,7 @@ check_dir_not_empty (HANDLE dir, path_conv &pc) int cnt = 1; do { + pfni = pfni_buf; while (pfni->NextEntryOffset) { if (++cnt > 2) @@ -677,7 +679,7 @@ check_dir_not_empty (HANDLE dir, path_conv &pc) pfni = (PFILE_NAMES_INFORMATION) ((caddr_t) pfni + pfni->NextEntryOffset); } } - while (NT_SUCCESS (NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, pfni, + while (NT_SUCCESS (NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, pfni_buf, bufsiz, FileNamesInformation, FALSE, NULL, FALSE))); return STATUS_SUCCESS; From c4102f82ddd97f77e32bda7aba84d5d4cc4028a7 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Thu, 14 Nov 2024 00:44:41 +0900 Subject: [PATCH 024/116] Cygwin: lockf: Fix access violation in lf_clearlock(). The commit ae181b0ff122 has a bug that the pointer is referred bofore NULL check in the function lf_clearlock(). This patch fixes that. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256750.html Fixes: ae181b0ff122 ("Cygwin: lockf: Make lockf() return ENOLCK when too many locks") Reported-by: Sebastian Feld Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit e7ef920d7d0dcff8cfe7a0c914f803b8c78900bb) --- winsup/cygwin/flock.cc | 6 ++++-- winsup/cygwin/release/3.5.5 | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/winsup/cygwin/flock.cc b/winsup/cygwin/flock.cc index 3821bddd67..794e66bd7e 100644 --- a/winsup/cygwin/flock.cc +++ b/winsup/cygwin/flock.cc @@ -1524,6 +1524,10 @@ lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl) lockf_t *lf = *head; lockf_t *overlap, **prev; int ovcase; + + if (lf == NOLOCKF) + return 0; + inode_t *node = lf->lf_inode; tmp_pathbuf tp; node->i_all_lf = (lockf_t *) tp.w_get (); @@ -1531,8 +1535,6 @@ lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl) uint32_t lock_cnt = node->get_lock_count (); bool first_loop = true; - if (lf == NOLOCKF) - return 0; prev = head; while ((ovcase = lf_findoverlap (lf, unlock, SELF, &prev, &overlap))) { diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index 3088f8682b..13982632b0 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -36,3 +36,6 @@ Fixes: - Fix potential stack corruption in rmdir() in a border case. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256774.html + +- Fix access violation in lf_clearlock() called from flock(). + Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256750.html From 67b31bc4ae1fc60d0407210a52e39bcbea0dc6f5 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Fri, 15 Nov 2024 21:58:22 +0900 Subject: [PATCH 025/116] Cygwin: flock: Fix overlap handling in lf_setlock() and lf_clearlock() Currently, create_lock_obj() can create multiple locks with the same lock range that have different version number. However, lf_setlock() and lf_clearlock() cannot handle this case appropriately. With this patch, make lf_setlock() and lf_clearlock() find overlap again even when ovcase = 1 (lock and overlap have the same lock range). Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256750.html Fixes: 2e560a092c1c ("* flock.cc (LOCK_OBJ_NAME_LEN): Change to accommodate extra lf_ver field.") Reported-by: Sebastian Feld Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit 8dee07a1f12682307be07e12a7fd8d5c8ecc1e2b) --- winsup/cygwin/flock.cc | 31 ++++++++++++++++++------------- winsup/cygwin/release/3.5.5 | 3 +++ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/winsup/cygwin/flock.cc b/winsup/cygwin/flock.cc index 794e66bd7e..b41cba5c70 100644 --- a/winsup/cygwin/flock.cc +++ b/winsup/cygwin/flock.cc @@ -1410,12 +1410,16 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) */ if (lock_cnt > MAX_LOCKF_CNT - room_for_clearlock) return ENOLCK; + /* Do not create a lock here. It should be done after all + overlaps have been removed. */ lf_wakelock (overlap, fhdl); - overlap->lf_type = lock->lf_type; - overlap->create_lock_obj (); - lock->lf_next = *clean; - *clean = lock; - break; + *prev = overlap->lf_next; + overlap->lf_next = *clean; + *clean = overlap; + /* We may have multiple versions (lf_ver) having same lock range. + Therefore, we need to find overlap repeatedly. (originally, + just 'break' here. */ + continue; case 2: /* overlap contains lock */ /* @@ -1563,10 +1567,16 @@ lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl) switch (ovcase) { case 1: /* overlap == lock */ + case 3: /* lock contains overlap */ *prev = overlap->lf_next; + lf = overlap->lf_next; overlap->lf_next = *clean; *clean = overlap; - break; + first_loop = false; + /* We may have multiple versions (lf_ver) having same lock range. + Therefore, we need to find overlap repeatedly. (originally, + just 'break' here. */ + continue; case 2: /* overlap contains lock: split it */ if (overlap->lf_start == unlock->lf_start) @@ -1582,13 +1592,8 @@ lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl) overlap->lf_next->create_lock_obj (); break; - case 3: /* lock contains overlap */ - *prev = overlap->lf_next; - lf = overlap->lf_next; - overlap->lf_next = *clean; - *clean = overlap; - first_loop = false; - continue; + /* case 3: */ /* lock contains overlap */ + /* Merged into case 1 */ case 4: /* overlap starts before lock */ overlap->lf_end = unlock->lf_start - 1; diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index 13982632b0..b70b91ed81 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -39,3 +39,6 @@ Fixes: - Fix access violation in lf_clearlock() called from flock(). Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256750.html + +- Fix NtCreateEvent() error in create_lock_ob() called from flock(). + Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256750.html From 2196f93fdadccebd71792ad190cfdf054d635994 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 20 Nov 2024 16:21:03 +0100 Subject: [PATCH 026/116] Cygwin: SetThreadName: avoid spurious debug message The following debug message occassionally shows up in strace output: SetThreadName: SetThreadDescription() failed. 00000000 10000000 The HRESULT of 0x10000000 is not an error, rather the set bit just indicates that this HRESULT has been created from an NTSTATUS value. Use the IS_ERROR() macro instead of just checking for S_OK. Fixes: d4689b99c686 ("Cygwin: Set threadnames with SetThreadDescription()") Signed-off-by: Corinna Vinschen (cherry picked from commit 21a2c9db6952954608cdf92638b411b15e7606c6) --- winsup/cygwin/miscfuncs.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc index 767384faa9..4220f62757 100644 --- a/winsup/cygwin/miscfuncs.cc +++ b/winsup/cygwin/miscfuncs.cc @@ -353,7 +353,7 @@ SetThreadName (DWORD dwThreadID, const char* threadName) WCHAR buf[bufsize]; bufsize = MultiByteToWideChar (CP_UTF8, 0, threadName, -1, buf, bufsize); HRESULT hr = SetThreadDescription (hThread, buf); - if (hr != S_OK) + if (IS_ERROR (hr)) { debug_printf ("SetThreadDescription() failed. %08x %08x\n", GetLastError (), hr); From 46474ecf5773bcfa216fe4943b8348f3aeb2bfcc Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Mon, 18 Nov 2024 00:07:12 +0900 Subject: [PATCH 027/116] Cygwin: sigtimedwait: Fix segfault when timeout is used Previously, two bugs exist in sigtimedwait(). One is, that since _my_tls.sigwait_mask was left non-zero if the signal arrives after the timeout, sigpacket::process() would wrongly try to handle it. The other is if a timeout occurs after sigpacket::process() is called, but not completed yet, the signal handler can be called accidentally. If the signal handler is set to SIG_DFL or SIG_IGN, access violation will occur in both cases. With this patch, in sigwait_common(), check if sigwait_mask == 0 to confirm that sigpacket::process() cleared it. In this case, do not treat WAIT_TIMEOUT, but call cygwait() again to retrieve the signal. Furthermore, sigpacket::process() checks whether timeout occurs in sigwait_common() and if timeout already happens, do not treat the signal as waited. In both cases, to avoid race issues, the code is guarded by cygtls::lock(). Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256762.html Fixes: 24ff42d79aab ("Cygwin: Implement sigtimedwait") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit 26144e4008cd8f7288f3387eea697bba4006e16f) --- winsup/cygwin/exceptions.cc | 5 ++++- winsup/cygwin/release/3.5.5 | 3 +++ winsup/cygwin/signal.cc | 12 ++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 3195d5719a..60c1f594f8 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -1527,11 +1527,14 @@ sigpacket::process () if ((HANDLE) *tls) tls->signal_debugger (si); - if (issig_wait) + tls->lock (); + if (issig_wait && tls->sigwait_mask != 0) { tls->sigwait_mask = 0; + tls->unlock (); goto dosig; } + tls->unlock (); if (handler == SIG_IGN) { diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index b70b91ed81..d91f2b92cd 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -42,3 +42,6 @@ Fixes: - Fix NtCreateEvent() error in create_lock_ob() called from flock(). Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256750.html + +- Fix segfault in sigtimedwait() when using timeout. + Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256762.html diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index 77152910b5..9ee6cf9959 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -615,6 +615,7 @@ sigwait_common (const sigset_t *set, siginfo_t *info, PLARGE_INTEGER waittime) set_signal_mask (_my_tls.sigwait_mask, *set); sig_dispatch_pending (true); +do_wait: switch (cygwait (NULL, waittime, cw_sig_eintr | cw_cancel | cw_cancel_self)) { @@ -640,6 +641,17 @@ sigwait_common (const sigset_t *set, siginfo_t *info, PLARGE_INTEGER waittime) } break; case WAIT_TIMEOUT: + _my_tls.lock (); + if (_my_tls.sigwait_mask == 0) + { + /* sigpacket::process() already started. + Will surely be signalled soon. */ + waittime = cw_infinite; + _my_tls.unlock (); + goto do_wait; + } + _my_tls.sigwait_mask = 0; + _my_tls.unlock (); set_errno (EAGAIN); break; default: From d06ba04550f96ae30daf38019ec80c99a39cf3f7 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 25 Nov 2024 15:02:36 +0100 Subject: [PATCH 028/116] Cygwin: sched_getscheduler: fix error handling Fixes: 6b2a2aa4af1e ("Add missing files.") Signed-off-by: Christian Franke --- winsup/cygwin/sched.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/sched.cc b/winsup/cygwin/sched.cc index 845fcef570..39d0ed96bb 100644 --- a/winsup/cygwin/sched.cc +++ b/winsup/cygwin/sched.cc @@ -140,7 +140,10 @@ int sched_getscheduler (pid_t pid) { if (pid < 0) - return ESRCH; + { + set_errno (EINVAL); + return -1; + } else return SCHED_FIFO; } From 96d729bc00a13a0c870701262745209e1ad59456 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 27 Nov 2024 16:39:37 +0100 Subject: [PATCH 029/116] Cygwin: sched_setscheduler: allow changes of the priority Behave like sched_setparam() if the requested policy is identical to the fixed value (SCHED_FIFO) returned by sched_getscheduler(). Fixes: 9a08b2c02eea ("* sched.cc: New file. Implement sched*.") Signed-off-by: Christian Franke (cherry picked from commit 522f3e921aa034c6a146021a918ce8b479a9111e) --- winsup/cygwin/release/3.5.5 | 3 +++ winsup/cygwin/sched.cc | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index d91f2b92cd..d41d168c6e 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -45,3 +45,6 @@ Fixes: - Fix segfault in sigtimedwait() when using timeout. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256762.html + +- sched_setscheduler(2) allows to change the priority if the policy is + equal to the value returned by sched_getscheduler(2). diff --git a/winsup/cygwin/sched.cc b/winsup/cygwin/sched.cc index 39d0ed96bb..a37e4f8b2f 100644 --- a/winsup/cygwin/sched.cc +++ b/winsup/cygwin/sched.cc @@ -402,8 +402,11 @@ int sched_setscheduler (pid_t pid, int policy, const struct sched_param *param) { + if (policy == SCHED_FIFO) /* returned by sched_getscheduler. */ + return sched_setparam (pid, param); + /* on win32, you can't change the scheduler. Doh! */ - set_errno (ENOSYS); + set_errno (EINVAL); return -1; } From 9af37caf780efa49b21fe1be8abc13037ce495ad Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Wed, 4 Dec 2024 13:00:39 +0900 Subject: [PATCH 030/116] Cygwin: termios: Trim buffer size for GetConsoleProcessList() Currently, the buffer of 128KB is passed to GetConsoleProcessList(). This causes page fault in the select() loop for console due to: https://github.com/microsoft/terminal/issues/18264 because the previous code calls GetConsoleProcessList() with large buffer and PeekConsoleInput() with small buffer alternately. With this patch, the minimum buffer size is used that is determined by GetConsoleProcessList() with small buffer passed. Addresses: https://cygwin.com/pipermail/cygwin/2024-December/256841.html Fixes: 72770148ad0a ("Cygwin: pty: Prevent pty from changing code page of parent console.") Reported-by: Steven Buehler Signed-off-by: Takashi Yano (cherry picked from commit 1a49c17840660bc0e493b7db2d9ce5289906049d) --- winsup/cygwin/fhandler/termios.cc | 14 ++++++++++++-- winsup/cygwin/release/3.5.5 | 3 +++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/winsup/cygwin/fhandler/termios.cc b/winsup/cygwin/fhandler/termios.cc index 585e6ac4ac..3cbdf7fca0 100644 --- a/winsup/cygwin/fhandler/termios.cc +++ b/winsup/cygwin/fhandler/termios.cc @@ -870,8 +870,18 @@ fhandler_termios::get_console_process_id (DWORD pid, bool match, DWORD *list = (DWORD *) tp.c_get (); const DWORD buf_size = NT_MAX_PATH / sizeof (DWORD); - DWORD num = GetConsoleProcessList (list, buf_size); - if (num == 0 || num > buf_size) + DWORD buf_size1 = 1; + DWORD num; + /* The buffer of too large size does not seem to be expected by new condrv. + https://github.com/microsoft/terminal/issues/18264#issuecomment-2515448548 + Use the minimum buffer size in the loop. */ + while ((num = GetConsoleProcessList (list, buf_size1)) > buf_size1) + { + if (num > buf_size) + return 0; + buf_size1 = num; + } + if (num == 0) return 0; DWORD res_pri = 0, res = 0; diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index d41d168c6e..7ccf28abf3 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -48,3 +48,6 @@ Fixes: - sched_setscheduler(2) allows to change the priority if the policy is equal to the value returned by sched_getscheduler(2). + +- Fix frequent page fault caused in Windows Terminal. + Addresses: https://cygwin.com/pipermail/cygwin/2024-December/256841.html From fff6372506cf162056f79038989b9eca76f7cd07 Mon Sep 17 00:00:00 2001 From: Radek Barton Date: Tue, 3 Dec 2024 16:36:45 -0500 Subject: [PATCH 031/116] Change various declarations to ANSI style to avoid problems with gcc 15 (cherry picked from commit d636b11d2e167cbcc310000ac1a977219b819fee) --- newlib/libc/posix/collate.c | 22 +-- newlib/libc/posix/collcmp.c | 6 +- newlib/libc/posix/engine.c | 82 +++++----- newlib/libc/posix/fnmatch.c | 11 +- newlib/libc/posix/regcomp.c | 265 +++++++++++++++++-------------- newlib/libc/posix/regerror.c | 7 +- newlib/libc/search/hash.c | 134 +++++++++------- newlib/libc/search/hash_bigkey.c | 102 ++++++------ newlib/libc/search/hash_buf.c | 42 ++--- newlib/libc/search/hash_func.c | 7 +- newlib/libc/search/hash_log2.c | 5 +- newlib/libc/search/hash_page.c | 127 +++++++++------ newlib/libc/search/tdestroy.c | 7 +- newlib/libc/search/twalk.c | 9 +- 14 files changed, 468 insertions(+), 358 deletions(-) diff --git a/newlib/libc/posix/collate.c b/newlib/libc/posix/collate.c index a2f62c978f..8e84895bac 100644 --- a/newlib/libc/posix/collate.c +++ b/newlib/libc/posix/collate.c @@ -58,8 +58,9 @@ struct __collate_st_chain_pri __collate_chain_pri_table[TABLE_SIZE]; void __collate_err(int ex, const char *f); int -__collate_load_tables(encoding) - char *encoding; +__collate_load_tables( + char *encoding +) { char buf[PATH_MAX]; FILE *fp; @@ -113,8 +114,9 @@ __collate_load_tables(encoding) } u_char * -__collate_substitute(s) - const u_char *s; +__collate_substitute( + const u_char *s +) { int dest_len, len, nlen; int delta = strlen((const char *) s); @@ -143,9 +145,12 @@ __collate_substitute(s) } void -__collate_lookup(t, len, prim, sec) - const u_char *t; - int *len, *prim, *sec; +__collate_lookup( + const u_char *t, + int *len, + int *prim, + int *sec +) { struct __collate_st_chain_pri *p2; @@ -165,8 +170,7 @@ __collate_lookup(t, len, prim, sec) } u_char * -__collate_strdup(s) - u_char *s; +__collate_strdup(u_char *s) { u_char *t = (u_char *) strdup((const char *) s); diff --git a/newlib/libc/posix/collcmp.c b/newlib/libc/posix/collcmp.c index 7770897619..675c4d80ae 100644 --- a/newlib/libc/posix/collcmp.c +++ b/newlib/libc/posix/collcmp.c @@ -40,8 +40,10 @@ * "[a-z]"-type ranges with national characters. */ -int __collate_range_cmp (c1, c2) - int c1, c2; +int __collate_range_cmp ( + int c1, + int c2 +) { static char s1[2], s2[2]; int ret; diff --git a/newlib/libc/posix/engine.c b/newlib/libc/posix/engine.c index c80834a0c2..cda7afa897 100644 --- a/newlib/libc/posix/engine.c +++ b/newlib/libc/posix/engine.c @@ -135,12 +135,13 @@ static char *pchar(int ch); == size_t nmatch, regmatch_t pmatch[], int eflags); */ static int /* 0 success, REG_NOMATCH failure */ -matcher(g, string, nmatch, pmatch, eflags) -struct re_guts *g; -char *string; -size_t nmatch; -regmatch_t pmatch[]; -int eflags; +matcher( + struct re_guts *g, + char *string, + size_t nmatch, + regmatch_t pmatch[], + int eflags +) { char *endp; int i; @@ -346,12 +347,13 @@ int eflags; == char *stop, sopno startst, sopno stopst); */ static char * /* == stop (success) always */ -dissect(m, start, stop, startst, stopst) -struct match *m; -char *start; -char *stop; -sopno startst; -sopno stopst; +dissect( + struct match *m, + char *start, + char *stop, + sopno startst, + sopno stopst +) { int i; sopno ss; /* start sop of current subRE */ @@ -539,13 +541,14 @@ sopno stopst; == char *stop, sopno startst, sopno stopst, sopno lev); */ static char * /* == stop (success) or NULL (failure) */ -backref(m, start, stop, startst, stopst, lev) -struct match *m; -char *start; -char *stop; -sopno startst; -sopno stopst; -sopno lev; /* PLUS nesting level */ +backref( + struct match *m, + char *start, + char *stop, + sopno startst, + sopno stopst, + sopno lev /* PLUS nesting level */ +) { int i; sopno ss; /* start sop of current subRE */ @@ -744,12 +747,13 @@ sopno lev; /* PLUS nesting level */ == char *stop, sopno startst, sopno stopst); */ static char * /* where tentative match ended, or NULL */ -fast(m, start, stop, startst, stopst) -struct match *m; -char *start; -char *stop; -sopno startst; -sopno stopst; +fast( + struct match *m, + char *start, + char *stop, + sopno startst, + sopno stopst +) { states st = m->st; states fresh = m->fresh; @@ -835,12 +839,13 @@ sopno stopst; == char *stop, sopno startst, sopno stopst); */ static char * /* where it ended */ -slow(m, start, stop, startst, stopst) -struct match *m; -char *start; -char *stop; -sopno startst; -sopno stopst; +slow( + struct match *m, + char *start, + char *stop, + sopno startst, + sopno stopst +) { states st = m->st; states empty = m->empty; @@ -931,13 +936,14 @@ sopno stopst; == #define NNONCHAR (CODEMAX-CHAR_MAX) */ static states -step(g, start, stop, bef, ch, aft) -struct re_guts *g; -sopno start; /* start state within strip */ -sopno stop; /* state after stop state within strip */ -states bef; /* states reachable before */ -int ch; /* character or NONCHAR code */ -states aft; /* states already known reachable after */ +step( + struct re_guts *g, + sopno start, /* start state within strip */ + sopno stop, /* state after stop state within strip */ + states bef, /* states reachable before */ + int ch, /* character or NONCHAR code */ + states aft /* states already known reachable after */ +) { cset *cs; sop s; diff --git a/newlib/libc/posix/fnmatch.c b/newlib/libc/posix/fnmatch.c index 1a679ab85e..1f062a54cf 100644 --- a/newlib/libc/posix/fnmatch.c +++ b/newlib/libc/posix/fnmatch.c @@ -163,11 +163,12 @@ fnmatch(pattern, string, flags) } static int -rangematch(pattern, test, flags, newp) - const char *pattern; - char test; - int flags; - char **newp; +rangematch( + const char *pattern, + char test, + int flags, + char **newp +) { int negate, ok; char c, c2; diff --git a/newlib/libc/posix/regcomp.c b/newlib/libc/posix/regcomp.c index c789746755..c839809468 100644 --- a/newlib/libc/posix/regcomp.c +++ b/newlib/libc/posix/regcomp.c @@ -303,9 +303,10 @@ int cflags; == static void p_ere(struct parse *p, int stop); */ static void -p_ere(p, stop) -struct parse *p; -int stop; /* character this ERE should end at */ +p_ere( + struct parse *p, + int stop /* character this ERE should end at */ +) { char c; sopno prevback = 0; @@ -349,8 +350,7 @@ int stop; /* character this ERE should end at */ == static void p_ere_exp(struct parse *p); */ static void -p_ere_exp(p) -struct parse *p; +p_ere_exp(struct parse *p) { char c; sopno pos; @@ -498,8 +498,7 @@ struct parse *p; == static void p_str(struct parse *p); */ static void -p_str(p) -struct parse *p; +p_str(struct parse *p) { (void)REQUIRE(MORE(), REG_EMPTY); while (MORE()) @@ -519,10 +518,11 @@ struct parse *p; * The amount of lookahead needed to avoid this kludge is excessive. */ static void -p_bre(p, end1, end2) -struct parse *p; -int end1; /* first terminating character */ -int end2; /* second terminating character */ +p_bre( + struct parse *p, + int end1, /* first terminating character */ + int end2 /* second terminating character */ +) { sopno start = HERE(); int first = 1; /* first subexpression? */ @@ -552,9 +552,10 @@ int end2; /* second terminating character */ == static int p_simp_re(struct parse *p, int starordinary); */ static int /* was the simple RE an unbackslashed $? */ -p_simp_re(p, starordinary) -struct parse *p; -int starordinary; /* is a leading * an ordinary character? */ +p_simp_re( + struct parse *p, + int starordinary /* is a leading * an ordinary character? */ +) { int c; int count; @@ -670,8 +671,7 @@ int starordinary; /* is a leading * an ordinary character? */ == static int p_count(struct parse *p); */ static int /* the value */ -p_count(p) -struct parse *p; +p_count(struct parse *p) { int count = 0; int ndigits = 0; @@ -693,8 +693,7 @@ struct parse *p; * no set operations are done. */ static void -p_bracket(p) -struct parse *p; +p_bracket(struct parse *p) { cset *cs = allocset(p); int invert = 0; @@ -767,9 +766,10 @@ struct parse *p; == static void p_b_term(struct parse *p, cset *cs); */ static void -p_b_term(p, cs) -struct parse *p; -cset *cs; +p_b_term( + struct parse *p, + cset *cs +) { char c; char start, finish; @@ -846,9 +846,10 @@ cset *cs; == static void p_b_cclass(struct parse *p, cset *cs); */ static void -p_b_cclass(p, cs) -struct parse *p; -cset *cs; +p_b_cclass( + struct parse *p, + cset *cs +) { int c; char *sp = p->next; @@ -942,9 +943,10 @@ cset *cs; * This implementation is incomplete. xxx */ static void -p_b_eclass(p, cs) -struct parse *p; -cset *cs; +p_b_eclass( + struct parse *p, + cset *cs +) { char c; @@ -957,8 +959,7 @@ cset *cs; == static char p_b_symbol(struct parse *p); */ static char /* value of symbol */ -p_b_symbol(p) -struct parse *p; +p_b_symbol(struct parse *p) { char value; @@ -977,9 +978,10 @@ struct parse *p; == static char p_b_coll_elem(struct parse *p, int endc); */ static char /* value of collating element */ -p_b_coll_elem(p, endc) -struct parse *p; -int endc; /* name ended by endc,']' */ +p_b_coll_elem( + struct parse *p, + int endc /* name ended by endc,']' */ +) { char *sp = p->next; struct cname *cp; @@ -1006,8 +1008,9 @@ int endc; /* name ended by endc,']' */ == static char othercase(int ch); */ static char /* if no counterpart, return ch */ -othercase(ch) -int ch; +othercase( + int ch +) { ch = (uch)ch; assert(isalpha(ch)); @@ -1026,9 +1029,10 @@ int ch; * Boy, is this implementation ever a kludge... */ static void -bothcases(p, ch) -struct parse *p; -int ch; +bothcases( + struct parse *p, + int ch +) { char *oldnext = p->next; char *oldend = p->end; @@ -1052,9 +1056,10 @@ int ch; == static void ordinary(struct parse *p, int ch); */ static void -ordinary(p, ch) -struct parse *p; -int ch; +ordinary( + struct parse *p, + int ch +) { cat_t *cap = p->g->categories; @@ -1074,8 +1079,9 @@ int ch; * Boy, is this implementation ever a kludge... */ static void -nonnewline(p) -struct parse *p; +nonnewline( + struct parse *p +) { char *oldnext = p->next; char *oldend = p->end; @@ -1098,11 +1104,12 @@ struct parse *p; == static void repeat(struct parse *p, sopno start, int from, int to); */ static void -repeat(p, start, from, to) -struct parse *p; -sopno start; /* operand from here to end of strip */ -int from; /* repeated from this number */ -int to; /* to this number of times (maybe INFINITY) */ +repeat( + struct parse *p, + sopno start, /* operand from here to end of strip */ + int from, /* repeated from this number */ + int to /* to this number of times (maybe INFINITY) */ +) { sopno finish = HERE(); # define N 2 @@ -1170,9 +1177,10 @@ int to; /* to this number of times (maybe INFINITY) */ == static int seterr(struct parse *p, int e); */ static int /* useless but makes type checking happy */ -seterr(p, e) -struct parse *p; -int e; +seterr( + struct parse *p, + int e +) { if (p->error == 0) /* keep earliest error condition */ p->error = e; @@ -1186,8 +1194,7 @@ int e; == static cset *allocset(struct parse *p); */ static cset * -allocset(p) -struct parse *p; +allocset(struct parse *p) { int no = p->g->ncsets++; size_t nc; @@ -1241,9 +1248,10 @@ struct parse *p; == static void freeset(struct parse *p, cset *cs); */ static void -freeset(p, cs) -struct parse *p; -cset *cs; +freeset( + struct parse *p, + cset *cs +) { int i; cset *top = &p->g->sets[p->g->ncsets]; @@ -1266,9 +1274,10 @@ cset *cs; * the same value! */ static int /* set number */ -freezeset(p, cs) -struct parse *p; -cset *cs; +freezeset( + struct parse *p, + cset *cs +) { short h = cs->hash; int i; @@ -1300,9 +1309,10 @@ cset *cs; == static int firstch(struct parse *p, cset *cs); */ static int /* character; there is no "none" value */ -firstch(p, cs) -struct parse *p; -cset *cs; +firstch( + struct parse *p, + cset *cs +) { int i; size_t css = (size_t)p->g->csetsize; @@ -1319,9 +1329,10 @@ cset *cs; == static int nch(struct parse *p, cset *cs); */ static int -nch(p, cs) -struct parse *p; -cset *cs; +nch( + struct parse *p, + cset *cs +) { int i; size_t css = (size_t)p->g->csetsize; @@ -1428,9 +1439,10 @@ char *cp; * is deferred. */ static void -mcinvert(p, cs) -struct parse *p; -cset *cs; +mcinvert( + struct parse *p, + cset *cs +) { assert(cs->multis == NULL); /* xxx */ } @@ -1443,9 +1455,10 @@ cset *cs; * is deferred. */ static void -mccase(p, cs) -struct parse *p; -cset *cs; +mccase( + struct parse *p, + cset *cs +) { assert(cs->multis == NULL); /* xxx */ } @@ -1455,9 +1468,10 @@ cset *cs; == static int isinsets(struct re_guts *g, int c); */ static int /* predicate */ -isinsets(g, c) -struct re_guts *g; -int c; +isinsets( + struct re_guts *g, + int c +) { uch *col; int i; @@ -1475,10 +1489,11 @@ int c; == static int samesets(struct re_guts *g, int c1, int c2); */ static int /* predicate */ -samesets(g, c1, c2) -struct re_guts *g; -int c1; -int c2; +samesets( + struct re_guts *g, + int c1, + int c2 +) { uch *col; int i; @@ -1497,9 +1512,10 @@ int c2; == static void categorize(struct parse *p, struct re_guts *g); */ static void -categorize(p, g) -struct parse *p; -struct re_guts *g; +categorize( + struct parse *p, + struct re_guts *g +) { cat_t *cats = g->categories; int c; @@ -1525,10 +1541,11 @@ struct re_guts *g; == static sopno dupl(struct parse *p, sopno start, sopno finish); */ static sopno /* start of duplicate */ -dupl(p, start, finish) -struct parse *p; -sopno start; /* from here */ -sopno finish; /* to this less one */ +dupl( + struct parse *p, + sopno start, /* from here */ + sopno finish /* to this less one */ +) { sopno ret = HERE(); sopno len = finish - start; @@ -1553,10 +1570,11 @@ sopno finish; /* to this less one */ * some changes to the data structures. Maybe later. */ static void -doemit(p, op, opnd) -struct parse *p; -sop op; -size_t opnd; +doemit( + struct parse *p, + sop op, + size_t opnd +) { /* avoid making error situations worse */ if (p->error != 0) @@ -1579,11 +1597,12 @@ size_t opnd; == static void doinsert(struct parse *p, sop op, size_t opnd, sopno pos); */ static void -doinsert(p, op, opnd, pos) -struct parse *p; -sop op; -size_t opnd; -sopno pos; +doinsert( + struct parse *p, + sop op, + size_t opnd, + sopno pos +) { sopno sn; sop s; @@ -1619,10 +1638,11 @@ sopno pos; == static void dofwd(struct parse *p, sopno pos, sop value); */ static void -dofwd(p, pos, value) -struct parse *p; -sopno pos; -sop value; +dofwd( + struct parse *p, + sopno pos, + sop value +) { /* avoid making error situations worse */ if (p->error != 0) @@ -1637,9 +1657,10 @@ sop value; == static void enlarge(struct parse *p, sopno size); */ static void -enlarge(p, size) -struct parse *p; -sopno size; +enlarge( + struct parse *p, + sopno size +) { sop *sp; @@ -1660,9 +1681,10 @@ sopno size; == static void stripsnug(struct parse *p, struct re_guts *g); */ static void -stripsnug(p, g) -struct parse *p; -struct re_guts *g; +stripsnug( + struct parse *p, + struct re_guts *g +) { g->nstates = p->slen; g->strip = (sop *)realloc((char *)p->strip, p->slen * sizeof(sop)); @@ -1683,9 +1705,10 @@ struct re_guts *g; * Note that must and mlen got initialized during setup. */ static void -findmust(p, g) -struct parse *p; -struct re_guts *g; +findmust( + struct parse *p, + struct re_guts *g +) { sop *scan; sop *start = NULL; @@ -1852,10 +1875,11 @@ struct re_guts *g; * re paths. */ static int -altoffset(scan, offset, mccs) -sop *scan; -int offset; -int mccs; +altoffset( + sop *scan, + int offset, + int mccs +) { int largest; int try; @@ -1932,9 +1956,10 @@ int mccs; * the value of the character from the text that was mismatched. */ static void -computejumps(p, g) -struct parse *p; -struct re_guts *g; +computejumps( + struct parse *p, + struct re_guts *g +) { int ch; int mindex; @@ -1978,9 +2003,10 @@ struct re_guts *g; * the search algorithm works. */ static void -computematchjumps(p, g) -struct parse *p; -struct re_guts *g; +computematchjumps( + struct parse *p, + struct re_guts *g +) { int mindex; /* General "must" iterator */ int suffix; /* Keeps track of matching suffix */ @@ -2056,9 +2082,10 @@ struct re_guts *g; == static sopno pluscount(struct parse *p, struct re_guts *g); */ static sopno /* nesting depth */ -pluscount(p, g) -struct parse *p; -struct re_guts *g; +pluscount( + struct parse *p, + struct re_guts *g +) { sop *scan; sop s; diff --git a/newlib/libc/posix/regerror.c b/newlib/libc/posix/regerror.c index a48d37c729..1b07b636c7 100644 --- a/newlib/libc/posix/regerror.c +++ b/newlib/libc/posix/regerror.c @@ -160,9 +160,10 @@ size_t errbuf_size; == static char *regatoi(const regex_t *preg, char *localbuf); */ static char * -regatoi(preg, localbuf) -const regex_t *preg; -char *localbuf; +regatoi( + const regex_t *preg, + char *localbuf +) { struct rerr *r; diff --git a/newlib/libc/search/hash.c b/newlib/libc/search/hash.c index 33ff275d94..f242337f5b 100644 --- a/newlib/libc/search/hash.c +++ b/newlib/libc/search/hash.c @@ -276,8 +276,9 @@ __hash_open (const char *file, } static int -hash_close(dbp) - DB *dbp; +hash_close( + DB *dbp +) { HTAB *hashp; int retval; @@ -292,8 +293,9 @@ hash_close(dbp) } static int -hash_fd(dbp) - const DB *dbp; +hash_fd( + const DB *dbp +) { HTAB *hashp; @@ -310,10 +312,11 @@ hash_fd(dbp) /************************** LOCAL CREATION ROUTINES **********************/ static HTAB * -init_hash(hashp, file, info) - HTAB *hashp; - const char *file; - const HASHINFO *info; +init_hash( + HTAB *hashp, + const char *file, + const HASHINFO *info +) { #ifdef __USE_INTERNAL_STAT64 struct stat64 statbuf; @@ -385,9 +388,10 @@ init_hash(hashp, file, info) * Returns 0 on No Error */ static int -init_htab(hashp, nelem) - HTAB *hashp; - int nelem; +init_htab( + HTAB *hashp, + int nelem +) { int nbuckets, nsegs; int l2; @@ -431,8 +435,9 @@ init_htab(hashp, nelem) * structure, freeing all allocated space. */ static int -hdestroy(hashp) - HTAB *hashp; +hdestroy( + HTAB *hashp +) { int i, save_errno; @@ -491,9 +496,10 @@ hdestroy(hashp) * -1 ERROR */ static int -hash_sync(dbp, flags) - const DB *dbp; - u_int flags; +hash_sync( + const DB *dbp, + u_int flags +) { HTAB *hashp; @@ -520,8 +526,9 @@ hash_sync(dbp, flags) * -1 indicates that errno should be set */ static int -flush_meta(hashp) - HTAB *hashp; +flush_meta( + HTAB *hashp +) { HASHHDR *whdrp; #if (BYTE_ORDER == LITTLE_ENDIAN) @@ -568,11 +575,12 @@ flush_meta(hashp) * -1 to indicate an internal ERROR (i.e. out of memory, etc) */ static int -hash_get(dbp, key, data, flag) - const DB *dbp; - const DBT *key; - DBT *data; - u_int flag; +hash_get( + const DB *dbp, + const DBT *key, + DBT *data, + u_int flag +) { HTAB *hashp; @@ -585,11 +593,12 @@ hash_get(dbp, key, data, flag) } static int -hash_put(dbp, key, data, flag) - const DB *dbp; - DBT *key; - const DBT *data; - u_int flag; +hash_put( + const DB *dbp, + DBT *key, + const DBT *data, + u_int flag +) { HTAB *hashp; @@ -608,10 +617,11 @@ hash_put(dbp, key, data, flag) } static int -hash_delete(dbp, key, flag) - const DB *dbp; - const DBT *key; - u_int flag; /* Ignored */ +hash_delete( + const DB *dbp, + const DBT *key, + u_int flag /* Ignored */ +) { HTAB *hashp; @@ -631,10 +641,12 @@ hash_delete(dbp, key, flag) * Assume that hashp has been set in wrapper routine. */ static int -hash_access(hashp, action, key, val) - HTAB *hashp; - ACTION action; - DBT *key, *val; +hash_access( + HTAB *hashp, + ACTION action, + DBT *key, + DBT *val +) { BUFHEAD *rbufp; BUFHEAD *bufp, *save_bufp; @@ -760,10 +772,12 @@ hash_access(hashp, action, key, val) } static int -hash_seq(dbp, key, data, flag) - const DB *dbp; - DBT *key, *data; - u_int flag; +hash_seq( + const DB *dbp, + DBT *key, + DBT *data, + u_int flag +) { __uint32_t bucket; BUFHEAD *bufp; @@ -850,8 +864,9 @@ hash_seq(dbp, key, data, flag) * -1 ==> Error */ extern int -__expand_table(hashp) - HTAB *hashp; +__expand_table( + HTAB *hashp +) { __uint32_t old_bucket, new_bucket; int dirsize, new_segnum, spare_ndx; @@ -905,9 +920,11 @@ __expand_table(hashp) * fails, then this routine can go away. */ static void * -hash_realloc(p_ptr, oldsize, newsize) - SEGMENT **p_ptr; - int oldsize, newsize; +hash_realloc( + SEGMENT **p_ptr, + int oldsize, + int newsize +) { void *p; @@ -921,10 +938,11 @@ hash_realloc(p_ptr, oldsize, newsize) } extern __uint32_t -__call_hash(hashp, k, len) - HTAB *hashp; - char *k; - int len; +__call_hash( + HTAB *hashp, + char *k, + int len +) { int n, bucket; @@ -941,9 +959,10 @@ __call_hash(hashp, k, len) * Returns 0 on success */ static int -alloc_segs(hashp, nsegs) - HTAB *hashp; - int nsegs; +alloc_segs( + HTAB *hashp, + int nsegs +) { int i; SEGMENT store; @@ -975,8 +994,10 @@ alloc_segs(hashp, nsegs) * Hashp->hdr needs to be byteswapped. */ static void -swap_header_copy(srcp, destp) - HASHHDR *srcp, *destp; +swap_header_copy( + HASHHDR *srcp, + HASHHDR *destp +) { int i; @@ -1004,8 +1025,9 @@ swap_header_copy(srcp, destp) } static void -swap_header(hashp) - HTAB *hashp; +swap_header( + HTAB *hashp +) { HASHHDR *hdrp; int i; diff --git a/newlib/libc/search/hash_bigkey.c b/newlib/libc/search/hash_bigkey.c index e110e46945..29a14502a7 100644 --- a/newlib/libc/search/hash_bigkey.c +++ b/newlib/libc/search/hash_bigkey.c @@ -83,10 +83,12 @@ static int collect_data(HTAB *, BUFHEAD *, int, int); *-1 ==> ERROR */ extern int -__big_insert(hashp, bufp, key, val) - HTAB *hashp; - BUFHEAD *bufp; - const DBT *key, *val; +__big_insert( + HTAB *hashp, + BUFHEAD *bufp, + const DBT *key, + const DBT *val +) { __uint16_t *p; int key_size, n, val_size; @@ -183,9 +185,10 @@ __big_insert(hashp, bufp, key, val) *-1 => ERROR */ extern int -__big_delete(hashp, bufp) - HTAB *hashp; - BUFHEAD *bufp; +__big_delete( + HTAB *hashp, + BUFHEAD *bufp +) { BUFHEAD *last_bfp, *rbufp; __uint16_t *bp, pageno; @@ -262,12 +265,13 @@ __big_delete(hashp, bufp) * -3 error */ extern int -__find_bigpair(hashp, bufp, ndx, key, size) - HTAB *hashp; - BUFHEAD *bufp; - int ndx; - char *key; - int size; +__find_bigpair( + HTAB *hashp, + BUFHEAD *bufp, + int ndx, + char *key, + int size +) { __uint16_t *bp; char *p; @@ -314,9 +318,10 @@ __find_bigpair(hashp, bufp, ndx, key, size) * bucket) */ extern __uint16_t -__find_last_page(hashp, bpp) - HTAB *hashp; - BUFHEAD **bpp; +__find_last_page( + HTAB *hashp, + BUFHEAD **bpp +) { BUFHEAD *bufp; __uint16_t *bp, pageno; @@ -355,12 +360,13 @@ __find_last_page(hashp, bpp) * index (index should always be 1). */ extern int -__big_return(hashp, bufp, ndx, val, set_current) - HTAB *hashp; - BUFHEAD *bufp; - int ndx; - DBT *val; - int set_current; +__big_return( + HTAB *hashp, + BUFHEAD *bufp, + int ndx, + DBT *val, + int set_current +) { BUFHEAD *save_p; __uint16_t *bp, len, off, save_addr; @@ -446,10 +452,12 @@ __big_return(hashp, bufp, ndx, val, set_current) * allocate a buffer and copy the data as you recurse up. */ static int -collect_data(hashp, bufp, len, set) - HTAB *hashp; - BUFHEAD *bufp; - int len, set; +collect_data( + HTAB *hashp, + BUFHEAD *bufp, + int len, + int set +) { __uint16_t *bp; char *p; @@ -502,11 +510,13 @@ collect_data(hashp, bufp, len, set) * Fill in the key and data for this big pair. */ extern int -__big_keydata(hashp, bufp, key, val, set) - HTAB *hashp; - BUFHEAD *bufp; - DBT *key, *val; - int set; +__big_keydata( + HTAB *hashp, + BUFHEAD *bufp, + DBT *key, + DBT *val, + int set +) { key->size = collect_key(hashp, bufp, 0, val, set); if (key->size == -1) @@ -520,12 +530,13 @@ __big_keydata(hashp, bufp, key, val, set) * collect the data, allocate a buffer and copy the key as you recurse up. */ static int -collect_key(hashp, bufp, len, val, set) - HTAB *hashp; - BUFHEAD *bufp; - int len; - DBT *val; - int set; +collect_key( + HTAB *hashp, + BUFHEAD *bufp, + int len, + DBT *val, + int set +) { BUFHEAD *xbp; char *p; @@ -565,15 +576,16 @@ collect_key(hashp, bufp, len, val, set) * -1 => error */ extern int -__big_split(hashp, op, np, big_keyp, addr, obucket, ret) - HTAB *hashp; - BUFHEAD *op; /* Pointer to where to put keys that go in old bucket */ - BUFHEAD *np; /* Pointer to new bucket page */ +__big_split( + HTAB *hashp, + BUFHEAD *op, /* Pointer to where to put keys that go in old bucket */ + BUFHEAD *np, /* Pointer to new bucket page */ /* Pointer to first page containing the big key/data */ - BUFHEAD *big_keyp; - int addr; /* Address of big_keyp */ - __uint32_t obucket;/* Old Bucket */ - SPLIT_RETURN *ret; + BUFHEAD *big_keyp, + int addr, /* Address of big_keyp */ + __uint32_t obucket,/* Old Bucket */ + SPLIT_RETURN *ret +) { BUFHEAD *tmpp; __uint16_t *tp; diff --git a/newlib/libc/search/hash_buf.c b/newlib/libc/search/hash_buf.c index 2b921681a7..7f8e90b679 100644 --- a/newlib/libc/search/hash_buf.c +++ b/newlib/libc/search/hash_buf.c @@ -107,11 +107,12 @@ static BUFHEAD *newbuf(HTAB *, __uint32_t, BUFHEAD *); * address you are seeking. */ extern BUFHEAD * -__get_buf(hashp, addr, prev_bp, newpage) - HTAB *hashp; - __uint32_t addr; - BUFHEAD *prev_bp; - int newpage; /* If prev_bp set, indicates a new overflow page. */ +__get_buf( + HTAB *hashp, + __uint32_t addr, + BUFHEAD *prev_bp, + int newpage /* If prev_bp set, indicates a new overflow page. */ +) { BUFHEAD *bp; __uint32_t is_disk_mask; @@ -162,10 +163,11 @@ __get_buf(hashp, addr, prev_bp, newpage) * If newbuf finds an error (returning NULL), it also sets errno. */ static BUFHEAD * -newbuf(hashp, addr, prev_bp) - HTAB *hashp; - __uint32_t addr; - BUFHEAD *prev_bp; +newbuf( + HTAB *hashp, + __uint32_t addr, + BUFHEAD *prev_bp +) { BUFHEAD *bp; /* The buffer we're going to use */ BUFHEAD *xbp; /* Temp pointer */ @@ -292,9 +294,10 @@ newbuf(hashp, addr, prev_bp) } extern void -__buf_init(hashp, nbytes) - HTAB *hashp; - int nbytes; +__buf_init( + HTAB *hashp, + int nbytes +) { BUFHEAD *bfp; int npages; @@ -317,9 +320,11 @@ __buf_init(hashp, nbytes) } extern int -__buf_free(hashp, do_free, to_disk) - HTAB *hashp; - int do_free, to_disk; +__buf_free( + HTAB *hashp, + int do_free, + int to_disk +) { BUFHEAD *bp; @@ -348,9 +353,10 @@ __buf_free(hashp, do_free, to_disk) } extern void -__reclaim_buf(hashp, bp) - HTAB *hashp; - BUFHEAD *bp; +__reclaim_buf( + HTAB *hashp, + BUFHEAD *bp +) { bp->ovfl = 0; bp->addr = 0; diff --git a/newlib/libc/search/hash_func.c b/newlib/libc/search/hash_func.c index 30263d0f63..ad8dd666d6 100644 --- a/newlib/libc/search/hash_func.c +++ b/newlib/libc/search/hash_func.c @@ -167,9 +167,10 @@ hash3(keyarg, len) /* Hash function from Chris Torek. */ static __uint32_t -hash4(keyarg, len) - const void *keyarg; - size_t len; +hash4( + const void *keyarg, + size_t len +) { const u_char *key; size_t loop; diff --git a/newlib/libc/search/hash_log2.c b/newlib/libc/search/hash_log2.c index 622c228474..0bc766af55 100644 --- a/newlib/libc/search/hash_log2.c +++ b/newlib/libc/search/hash_log2.c @@ -40,8 +40,9 @@ static char sccsid[] = "@(#)hash_log2.c 8.2 (Berkeley) 5/31/94"; #include "db_local.h" __uint32_t -__log2(num) - __uint32_t num; +__log2( + __uint32_t num +) { __uint32_t i, limit; diff --git a/newlib/libc/search/hash_page.c b/newlib/libc/search/hash_page.c index 9d15b0cb70..c073f49dfc 100644 --- a/newlib/libc/search/hash_page.c +++ b/newlib/libc/search/hash_page.c @@ -91,9 +91,11 @@ static int ugly_split * stuff on. */ static void -putpair(p, key, val) - char *p; - const DBT *key, *val; +putpair( + char *p, + const DBT *key, + const DBT *val +) { __uint16_t *bp, n, off; @@ -123,10 +125,11 @@ putpair(p, key, val) * -1 error */ extern int -__delpair(hashp, bufp, ndx) - HTAB *hashp; - BUFHEAD *bufp; - int ndx; +__delpair( + HTAB *hashp, + BUFHEAD *bufp, + int ndx +) { __uint16_t *bp, newoff; int n; @@ -176,9 +179,11 @@ __delpair(hashp, bufp, ndx) * -1 ==> Error */ extern int -__split_page(hashp, obucket, nbucket) - HTAB *hashp; - __uint32_t obucket, nbucket; +__split_page( + HTAB *hashp, + __uint32_t obucket, + __uint32_t nbucket +) { BUFHEAD *new_bufp, *old_bufp; __uint16_t *ino; @@ -272,12 +277,14 @@ __split_page(hashp, obucket, nbucket) * -1 ==> failure */ static int -ugly_split(hashp, obucket, old_bufp, new_bufp, copyto, moved) - HTAB *hashp; - __uint32_t obucket; /* Same as __split_page. */ - BUFHEAD *old_bufp, *new_bufp; - int copyto; /* First byte on page which contains key/data values. */ - int moved; /* Number of pairs moved to new page. */ +ugly_split( + HTAB *hashp, + __uint32_t obucket, /* Same as __split_page. */ + BUFHEAD *old_bufp, + BUFHEAD *new_bufp, + int copyto, /* First byte on page which contains key/data values. */ + int moved /* Number of pairs moved to new page. */ +) { BUFHEAD *bufp; /* Buffer header for ino */ __uint16_t *ino; /* Page keys come off of */ @@ -393,10 +400,12 @@ ugly_split(hashp, obucket, old_bufp, new_bufp, copyto, moved) * 1 ==> failure */ extern int -__addel(hashp, bufp, key, val) - HTAB *hashp; - BUFHEAD *bufp; - const DBT *key, *val; +__addel( + HTAB *hashp, + BUFHEAD *bufp, + const DBT *key, + const DBT *val +) { __uint16_t *bp, *sop; int do_expand; @@ -460,9 +469,10 @@ __addel(hashp, bufp, key, val) * NULL on error */ extern BUFHEAD * -__add_ovflpage(hashp, bufp) - HTAB *hashp; - BUFHEAD *bufp; +__add_ovflpage( + HTAB *hashp, + BUFHEAD *bufp +) { __uint16_t *sp; __uint16_t ndx, ovfl_num; @@ -513,11 +523,14 @@ __add_ovflpage(hashp, bufp) * -1 indicates FAILURE */ extern int -__get_page(hashp, p, bucket, is_bucket, is_disk, is_bitmap) - HTAB *hashp; - char *p; - __uint32_t bucket; - int is_bucket, is_disk, is_bitmap; +__get_page( + HTAB *hashp, + char *p, + __uint32_t bucket, + int is_bucket, + int is_disk, + int is_bitmap +) { int fd, page, size; int rsize; @@ -573,11 +586,13 @@ __get_page(hashp, p, bucket, is_bucket, is_disk, is_bitmap) * -1 ==>failure */ extern int -__put_page(hashp, p, bucket, is_bucket, is_bitmap) - HTAB *hashp; - char *p; - __uint32_t bucket; - int is_bucket, is_bitmap; +__put_page( + HTAB *hashp, + char *p, + __uint32_t bucket, + int is_bucket, + int is_bitmap +) { int fd, page, size; int wsize; @@ -622,9 +637,12 @@ __put_page(hashp, p, bucket, is_bucket, is_bitmap) * once they are read in. */ extern int -__ibitmap(hashp, pnum, nbits, ndx) - HTAB *hashp; - int pnum, nbits, ndx; +__ibitmap( + HTAB *hashp, + int pnum, + int nbits, + int ndx +) { __uint32_t *ip; int clearbytes, clearints; @@ -645,8 +663,9 @@ __ibitmap(hashp, pnum, nbits, ndx) } static __uint32_t -first_free(map) - __uint32_t map; +first_free( + __uint32_t map +) { __uint32_t i, mask; @@ -660,8 +679,9 @@ first_free(map) } static __uint16_t -overflow_page(hashp) - HTAB *hashp; +overflow_page( + HTAB *hashp +) { __uint32_t *freep = NULL; int max_free, offset, splitnum; @@ -808,9 +828,10 @@ overflow_page(hashp) * Mark this overflow page as free. */ extern void -__free_ovflpage(hashp, obufp) - HTAB *hashp; - BUFHEAD *obufp; +__free_ovflpage( + HTAB *hashp, + BUFHEAD *obufp +) { __uint16_t addr; __uint32_t *freep; @@ -854,8 +875,9 @@ __free_ovflpage(hashp, obufp) * -1 failure */ static int -open_temp(hashp) - HTAB *hashp; +open_temp( + HTAB *hashp +) { sigset_t set, oset; static char namestr[] = "_hashXXXXXX"; @@ -878,9 +900,11 @@ open_temp(hashp) * an overflow pair, so we need to shift things. */ static void -squeeze_key(sp, key, val) - __uint16_t *sp; - const DBT *key, *val; +squeeze_key( + __uint16_t *sp, + const DBT *key, + const DBT *val +) { char *p; __uint16_t free_space, n, off, pageno; @@ -905,9 +929,10 @@ squeeze_key(sp, key, val) } static __uint32_t * -fetch_bitmap(hashp, ndx) - HTAB *hashp; - int ndx; +fetch_bitmap( + HTAB *hashp, + int ndx +) { if (ndx >= hashp->nmaps) return (NULL); diff --git a/newlib/libc/search/tdestroy.c b/newlib/libc/search/tdestroy.c index 04c6b70520..23c4b0e70f 100644 --- a/newlib/libc/search/tdestroy.c +++ b/newlib/libc/search/tdestroy.c @@ -26,9 +26,10 @@ __RCSID("$NetBSD: tdelete.c,v 1.2 1999/09/16 11:45:37 lukem Exp $"); /* Walk the nodes of a tree */ static void -trecurse(root, free_action) - node_t *root; /* Root of the tree to be walked */ - void (*free_action)(void *); +trecurse( + node_t *root, /* Root of the tree to be walked */ + void (*free_action)(void *) +) { if (root->llink != NULL) trecurse(root->llink, free_action); diff --git a/newlib/libc/search/twalk.c b/newlib/libc/search/twalk.c index 02ef52242f..7aec6e4dd2 100644 --- a/newlib/libc/search/twalk.c +++ b/newlib/libc/search/twalk.c @@ -28,10 +28,11 @@ static void trecurse(const node_t *, /* Walk the nodes of a tree */ static void -trecurse(root, action, level) - const node_t *root; /* Root of the tree to be walked */ - void (*action)(const void *, VISIT, int); - int level; +trecurse( + const node_t *root, /* Root of the tree to be walked */ + void (*action)(const void *, VISIT, int), + int level +) { if (root->llink == NULL && root->rlink == NULL) From c8e978a3e50e6bd88110eee20188612e3e9e4b3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Barto=C5=88?= Date: Wed, 4 Dec 2024 12:33:23 +0100 Subject: [PATCH 032/116] Cygwin: Fix compatibility with GCC 15 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Radek Bartoň (cherry picked from commit c79954439e6d91dc6f421a761953f0d935c5f3d5) --- winsup/cygwin/libc/fts.c | 3 +- winsup/cygwin/libc/inet_network.c | 3 +- winsup/testsuite/libltp/include/test.h | 2 +- winsup/testsuite/libltp/include/usctest.h | 2 +- winsup/testsuite/libltp/include/write_log.h | 2 +- winsup/testsuite/libltp/lib/dataascii.c | 24 +++++----- winsup/testsuite/libltp/lib/databin.c | 24 +++++----- winsup/testsuite/libltp/lib/datapid.c | 24 +++++----- winsup/testsuite/libltp/lib/forker.c | 16 +++---- winsup/testsuite/libltp/lib/parse_opts.c | 20 ++++---- winsup/testsuite/libltp/lib/pattern.c | 26 +++++----- winsup/testsuite/libltp/lib/search_path.c | 11 +++-- winsup/testsuite/libltp/lib/str_to_bytes.c | 9 ++-- .../testsuite/libltp/lib/string_to_tokens.c | 2 +- winsup/testsuite/libltp/lib/tst_res.c | 2 - winsup/testsuite/libltp/lib/tst_sig.c | 4 +- winsup/testsuite/libltp/lib/write_log.c | 48 ++++++++++--------- 17 files changed, 116 insertions(+), 106 deletions(-) diff --git a/winsup/cygwin/libc/fts.c b/winsup/cygwin/libc/fts.c index 1826d22137..6f060e54e3 100644 --- a/winsup/cygwin/libc/fts.c +++ b/winsup/cygwin/libc/fts.c @@ -1111,8 +1111,7 @@ fts_padjust(FTS *sp, FTSENT *head) } static size_t -fts_maxarglen(argv) - char * const *argv; +fts_maxarglen(char * const *argv) { size_t len, max; diff --git a/winsup/cygwin/libc/inet_network.c b/winsup/cygwin/libc/inet_network.c index 43a394cf45..17b61f7aab 100644 --- a/winsup/cygwin/libc/inet_network.c +++ b/winsup/cygwin/libc/inet_network.c @@ -56,8 +56,7 @@ __FBSDID("$FreeBSD$"); * network numbers. */ in_addr_t -cygwin_inet_network(cp) - const char *cp; +cygwin_inet_network(const char *cp) { in_addr_t val, base, n; char c; diff --git a/winsup/testsuite/libltp/include/test.h b/winsup/testsuite/libltp/include/test.h index 757f3b8a1d..af7c3c0c88 100644 --- a/winsup/testsuite/libltp/include/test.h +++ b/winsup/testsuite/libltp/include/test.h @@ -225,7 +225,7 @@ extern void tt_exit(); extern int t_environ(); extern void t_breakum(char *tcid, int total, int typ, char *msg, void (*fnc)()); -extern void tst_sig(int fork_flag, void (*handler)(), void (*cleanup)()); +extern void tst_sig(int fork_flag, void (*handler)(int), void (*cleanup)()); extern void tst_tmpdir(); extern void tst_rmdir(); diff --git a/winsup/testsuite/libltp/include/usctest.h b/winsup/testsuite/libltp/include/usctest.h index 637635a251..08db49551d 100644 --- a/winsup/testsuite/libltp/include/usctest.h +++ b/winsup/testsuite/libltp/include/usctest.h @@ -198,7 +198,7 @@ struct tblock { * in the macros that follow. ***********************************************************************/ extern struct tblock tblock; -extern void STD_go(); +extern void STD_go(int); extern int (*_TMP_FUNC)(void); extern void STD_opts_help(); diff --git a/winsup/testsuite/libltp/include/write_log.h b/winsup/testsuite/libltp/include/write_log.h index 784d5b3ebb..505d2c08a8 100644 --- a/winsup/testsuite/libltp/include/write_log.h +++ b/winsup/testsuite/libltp/include/write_log.h @@ -154,7 +154,7 @@ extern int wlog_close(struct wlog_file *wfile); extern int wlog_record_write(struct wlog_file *wfile, struct wlog_rec *wrec, long offset); extern int wlog_scan_backward(struct wlog_file *wfile, int nrecs, - int (*func)(struct wlog_rec *rec), + int (*func)(struct wlog_rec *rec, long), long data); #else int wlog_open(); diff --git a/winsup/testsuite/libltp/lib/dataascii.c b/winsup/testsuite/libltp/lib/dataascii.c index 5bc2018527..41ed440c01 100644 --- a/winsup/testsuite/libltp/lib/dataascii.c +++ b/winsup/testsuite/libltp/lib/dataascii.c @@ -43,11 +43,12 @@ static char Errmsg[80]; int -dataasciigen(listofchars, buffer, bsize, offset) -char *listofchars; /* a null terminated list of characters */ -char *buffer; -int bsize; -int offset; +dataasciigen( + char *listofchars, /* a null terminated list of characters */ + char *buffer, + int bsize, + int offset +) { int cnt; int total; @@ -78,12 +79,13 @@ int offset; } /* end of dataasciigen */ int -dataasciichk(listofchars, buffer, bsize, offset, errmsg) -char *listofchars; /* a null terminated list of characters */ -char *buffer; -int bsize; -int offset; -char **errmsg; +dataasciichk( + char *listofchars, /* a null terminated list of characters */ + char *buffer, + int bsize, + int offset, + char **errmsg +) { int cnt; int total; diff --git a/winsup/testsuite/libltp/lib/databin.c b/winsup/testsuite/libltp/lib/databin.c index e43fef4e46..6cf27f77c2 100644 --- a/winsup/testsuite/libltp/lib/databin.c +++ b/winsup/testsuite/libltp/lib/databin.c @@ -42,11 +42,12 @@ static char Errmsg[80]; void -databingen (mode, buffer, bsize, offset) -int mode; /* either a, c, r, o, z or C */ -unsigned char *buffer; /* buffer pointer */ -int bsize; /* size of buffer */ -int offset; /* offset into the file where buffer starts */ +databingen ( + int mode, /* either a, c, r, o, z or C */ + unsigned char *buffer, /* buffer pointer */ + int bsize, /* size of buffer */ + int offset /* offset into the file where buffer starts */ +) { int ind; @@ -89,12 +90,13 @@ int ind; * < 0 : no error ***********************************************************************/ int -databinchk(mode, buffer, bsize, offset, errmsg) -int mode; /* either a, c, r, z, o, or C */ -unsigned char *buffer; /* buffer pointer */ -int bsize; /* size of buffer */ -int offset; /* offset into the file where buffer starts */ -char **errmsg; +databinchk( + int mode, /* either a, c, r, z, o, or C */ + unsigned char *buffer, /* buffer pointer */ + int bsize, /* size of buffer */ + int offset, /* offset into the file where buffer starts */ + char **errmsg +) { int cnt; unsigned char *chr; diff --git a/winsup/testsuite/libltp/lib/datapid.c b/winsup/testsuite/libltp/lib/datapid.c index 9414eae901..ca091311bf 100644 --- a/winsup/testsuite/libltp/lib/datapid.c +++ b/winsup/testsuite/libltp/lib/datapid.c @@ -83,11 +83,12 @@ static char Errmsg[80]; * Thus, offset 8 is in middle of word 1 ***********************************************************************/ int -datapidgen(pid, buffer, bsize, offset) -int pid; -char *buffer; -int bsize; -int offset; +datapidgen( + int pid, + char *buffer, + int bsize, + int offset +) { #if CRAY @@ -178,12 +179,13 @@ printf("partial at end\n"); * ***********************************************************************/ int -datapidchk(pid, buffer, bsize, offset, errmsg) -int pid; -char *buffer; -int bsize; -int offset; -char **errmsg; +datapidchk( + int pid, + char *buffer, + int bsize, + int offset, + char **errmsg +) { #if CRAY diff --git a/winsup/testsuite/libltp/lib/forker.c b/winsup/testsuite/libltp/lib/forker.c index 99bc585501..65f1036a3e 100644 --- a/winsup/testsuite/libltp/lib/forker.c +++ b/winsup/testsuite/libltp/lib/forker.c @@ -133,8 +133,7 @@ int Forker_npids=0; /* number of entries in Forker_pids */ * !0 : if fork failed, the return value will be the errno. ***********************************************************************/ int -background(prefix) -char *prefix; +background(char *prefix) { switch (fork()) { case -1: @@ -159,12 +158,13 @@ char *prefix; * ***********************************************************************/ int -forker(ncopies, mode, prefix) -int ncopies; -int mode; /* 0 - all childern of parent, 1 - only 1 direct child */ -char *prefix; /* if ! NULL, an message will be printed to stderr */ - /* if fork fails. The prefix (program name) will */ - /* preceed the message */ +forker( + int ncopies, + int mode, /* 0 - all childern of parent, 1 - only 1 direct child */ + char *prefix /* if ! NULL, an message will be printed to stderr */ + /* if fork fails. The prefix (program name) will */ + /* preceed the message */ +) { int cnt; int pid; diff --git a/winsup/testsuite/libltp/lib/parse_opts.c b/winsup/testsuite/libltp/lib/parse_opts.c index 1f41bfdd26..4a3c330875 100644 --- a/winsup/testsuite/libltp/lib/parse_opts.c +++ b/winsup/testsuite/libltp/lib/parse_opts.c @@ -198,7 +198,11 @@ int STD_ERRNO_LIST[USC_MAX_ERRNO]; #define STRLEN 2048 static char Mesg2[STRLEN]; /* holds possible return string */ -static void usc_recressive_func(); +static void usc_recressive_func( + int cnt, + int max, + struct usc_bigstack_t **bstack +); /* * Define bits for options that might have env variable default @@ -633,7 +637,7 @@ usc_global_setup_hook() if ( STD_PAUSE ) { _TMP_FUNC = (int (*)())signal(SIGUSR1, STD_go); pause(); - signal(SIGUSR1, (void (*)())_TMP_FUNC); + signal(SIGUSR1, (_sig_func_ptr)_TMP_FUNC); } @@ -693,8 +697,7 @@ get_current_time() * counter integer is supplied by the user program. ***********************************************************************/ int -usc_test_looping(counter) -int counter; +usc_test_looping(int counter) { static int first_time = 1; static int stop_time = 0; /* stop time in rtc or usecs */ @@ -803,10 +806,11 @@ int counter; * This function recressively calls itself max times. */ static void -usc_recressive_func(cnt, max, bstack) -int cnt; -int max; -struct usc_bigstack_t bstack; +usc_recressive_func( + int cnt, + int max, + struct usc_bigstack_t **bstack +) { if ( cnt < max ) usc_recressive_func(cnt+1, max, bstack); diff --git a/winsup/testsuite/libltp/lib/pattern.c b/winsup/testsuite/libltp/lib/pattern.c index 7f4d5873e0..5a88bfd3b8 100644 --- a/winsup/testsuite/libltp/lib/pattern.c +++ b/winsup/testsuite/libltp/lib/pattern.c @@ -38,12 +38,13 @@ */ int -pattern_check(buf, buflen, pat, patlen, patshift) -char *buf; -int buflen; -char *pat; -int patlen; -int patshift; +pattern_check( + char *buf, + int buflen, + char *pat, + int patlen, + int patshift +) { int nb, ncmp, nleft; char *cp; @@ -105,12 +106,13 @@ int patshift; } int -pattern_fill(buf, buflen, pat, patlen, patshift) -char *buf; -int buflen; -char *pat; -int patlen; -int patshift; +pattern_fill( + char *buf, + int buflen, + char *pat, + int patlen, + int patshift +) { int trans, ncopied, nleft; char *cp; diff --git a/winsup/testsuite/libltp/lib/search_path.c b/winsup/testsuite/libltp/lib/search_path.c index 697b4037b2..f6936094a1 100644 --- a/winsup/testsuite/libltp/lib/search_path.c +++ b/winsup/testsuite/libltp/lib/search_path.c @@ -103,11 +103,12 @@ char **argv; /* */ int -search_path(cmd, res_path, access_mode, fullpath) -const char *cmd; /* The requested filename */ -char *res_path; /* The resulting path or error mesg */ -int access_mode; /* the mode used by access(2) */ -int fullpath; /* if set, cwd will be prepended to all non-full paths */ +search_path( + const char *cmd, /* The requested filename */ + char *res_path, /* The resulting path or error mesg */ + int access_mode, /* the mode used by access(2) */ + int fullpath /* if set, cwd will be prepended to all non-full paths */ +) { char *cp; /* used to scan PATH for directories */ int ret; /* return value from access */ diff --git a/winsup/testsuite/libltp/lib/str_to_bytes.c b/winsup/testsuite/libltp/lib/str_to_bytes.c index beecb71b61..70157dcdee 100644 --- a/winsup/testsuite/libltp/lib/str_to_bytes.c +++ b/winsup/testsuite/libltp/lib/str_to_bytes.c @@ -75,8 +75,7 @@ #define T_MULT 1099511627776 /* tera or 2^40 */ int -str_to_bytes(s) -char *s; +str_to_bytes(char *s) { char mult, junk; int nconv; @@ -110,8 +109,7 @@ char *s; } long -str_to_lbytes(s) -char *s; +str_to_lbytes(char *s) { char mult, junk; long nconv; @@ -150,8 +148,7 @@ char *s; */ long long -str_to_llbytes(s) -char *s; +str_to_llbytes(char *s) { char mult, junk; long nconv; diff --git a/winsup/testsuite/libltp/lib/string_to_tokens.c b/winsup/testsuite/libltp/lib/string_to_tokens.c index 6f0d775dd9..a2b3a76174 100644 --- a/winsup/testsuite/libltp/lib/string_to_tokens.c +++ b/winsup/testsuite/libltp/lib/string_to_tokens.c @@ -80,7 +80,7 @@ int string_to_tokens(char *arg_string, char *arg_array[], int array_size, char *separator) { int num_toks = 0; /* number of tokens found */ - char *strtok(); + char *strtok(char *, const char *); if ( arg_array == NULL || array_size <= 1 || separator == NULL ) return -1; diff --git a/winsup/testsuite/libltp/lib/tst_res.c b/winsup/testsuite/libltp/lib/tst_res.c index 99767ec9ba..731dcbc1b4 100644 --- a/winsup/testsuite/libltp/lib/tst_res.c +++ b/winsup/testsuite/libltp/lib/tst_res.c @@ -563,8 +563,6 @@ tst_exit() int tst_environ() { - FILE *fdopen(); - if ( (T_out = fdopen(dup(fileno(stdout)), "w")) == NULL ) return(-1); else diff --git a/winsup/testsuite/libltp/lib/tst_sig.c b/winsup/testsuite/libltp/lib/tst_sig.c index f5b64b666c..976b5eecb1 100644 --- a/winsup/testsuite/libltp/lib/tst_sig.c +++ b/winsup/testsuite/libltp/lib/tst_sig.c @@ -81,7 +81,7 @@ void (*T_cleanup)(); /* pointer to cleanup function */ extern int errno; -static void def_handler(); /* default signal handler */ +static void def_handler(int); /* default signal handler */ /**************************************************************************** * tst_sig() : set-up to catch unexpected signals. fork_flag is set to NOFORK @@ -93,7 +93,7 @@ static void def_handler(); /* default signal handler */ ***************************************************************************/ void -tst_sig(int fork_flag, void (*handler)(), void (*cleanup)()) +tst_sig(int fork_flag, void (*handler)(int), void (*cleanup)()) { char mesg[MAXMESG]; /* message buffer for tst_res */ int sig; diff --git a/winsup/testsuite/libltp/lib/write_log.c b/winsup/testsuite/libltp/lib/write_log.c index 8104b05acd..bfbf6adfaa 100644 --- a/winsup/testsuite/libltp/lib/write_log.c +++ b/winsup/testsuite/libltp/lib/write_log.c @@ -115,10 +115,11 @@ static int wlog_rec_unpack(); */ int -wlog_open(wfile, trunc, mode) -struct wlog_file *wfile; -int trunc; -int mode; +wlog_open( + struct wlog_file *wfile, + int trunc, + int mode +) { int omask, oflags; @@ -166,8 +167,7 @@ int mode; */ int -wlog_close(wfile) -struct wlog_file *wfile; +wlog_close(struct wlog_file *wfile) { close(wfile->w_afd); close(wfile->w_rfd); @@ -201,10 +201,11 @@ struct wlog_file *wfile; */ int -wlog_record_write(wfile, wrec, offset) -struct wlog_file *wfile; -struct wlog_rec *wrec; -long offset; +wlog_record_write( + struct wlog_file *wfile, + struct wlog_rec *wrec, + long offset +) { int reclen; char wbuf[WLOG_REC_MAX_SIZE + 2]; @@ -249,11 +250,12 @@ long offset; */ int -wlog_scan_backward(wfile, nrecs, func, data) -struct wlog_file *wfile; -int nrecs; -int (*func)(); -long data; +wlog_scan_backward( + struct wlog_file *wfile, + int nrecs, + int (*func)(struct wlog_rec*, long), + long data +) { int fd, leftover, nbytes, recnum, reclen, rval; off_t offset; @@ -381,10 +383,11 @@ long data; */ static int -wlog_rec_pack(wrec, buf, flag) -struct wlog_rec *wrec; -char *buf; -int flag; +wlog_rec_pack( + struct wlog_rec *wrec, + char *buf, + int flag +) { char *file, *host, *pattern; struct wlog_rec_disk *wrecd; @@ -430,9 +433,10 @@ int flag; } static int -wlog_rec_unpack(wrec, buf) -struct wlog_rec *wrec; -char *buf; +wlog_rec_unpack( + struct wlog_rec *wrec, + char *buf +) { char *file, *host, *pattern; struct wlog_rec_disk *wrecd; From bb854e0f112ce69c52e0511bbfc423577c57f2a0 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 4 Dec 2024 22:54:18 +0100 Subject: [PATCH 033/116] Cygwin: try_to_bin: transpose deleted file name to valid Unicode chars Since commit 314c2d2fedc5f ("* syscalls.cc (try_to_bin): Handle remote shares as well.") try_to_bin() transposes the .cyg prefix for temporary files to invalid low surrogate halfs on filesystems setting the FILE_UNICODE_ON_DISK flag. This works on NTFS, but not necessarily on other filesystems, which often require all chars in a filename to be valid Unicode chars. Fix this by transposing into the private use area instead. Fixes: 314c2d2fedc5f ("* syscalls.cc (try_to_bin): Handle remote shares as well.") Signed-off-by: Corinna Vinschen (cherry picked from commit 0924d5f1078b368b6e290d11c9f3d57bc7767576) --- winsup/cygwin/release/3.5.5 | 3 +++ winsup/cygwin/syscalls.cc | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index 7ccf28abf3..d5063af164 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -51,3 +51,6 @@ Fixes: - Fix frequent page fault caused in Windows Terminal. Addresses: https://cygwin.com/pipermail/cygwin/2024-December/256841.html + +- Fix using invalid chars in temporary file names for deleted files. + Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256813.html diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 1d9308ef46..11033bca5e 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -340,14 +340,14 @@ try_to_bin (path_conv &pc, HANDLE &fh, ACCESS_MASK access, ULONG flags) else { /* Create unique filename. Start with a dot, followed by "cyg" - transposed into the Unicode low surrogate area (U+dc00) on file - systems supporting Unicode (except Samba), followed by the inode - number in hex, followed by a path hash in hex. The combination - allows to remove multiple hardlinks to the same file. */ + transposed to the Unicode private use area in the U+f700 area + on file systems supporting Unicode (except Samba), followed by + the inode number in hex, followed by a path hash in hex. The + combination allows to remove multiple hardlinks to the same file. */ RtlAppendUnicodeToString (&recycler, (pc.fs_flags () & FILE_UNICODE_ON_DISK && !pc.fs_is_samba ()) - ? L".\xdc63\xdc79\xdc67" : L".cyg"); + ? L".\xf763\xf779\xf767" : L".cyg"); pfii = (PFILE_INTERNAL_INFORMATION) infobuf; status = NtQueryInformationFile (fh, &io, pfii, sizeof *pfii, FileInternalInformation); From bbf8484a5b4fb5bcae024c04a8d84e53834e8b79 Mon Sep 17 00:00:00 2001 From: Kito Cheng Date: Thu, 5 Dec 2024 16:39:56 +0800 Subject: [PATCH 034/116] libm/common: Fix nextafter and nextafterf when x == y That according to C99/POSIX, nextafter(x,y) should return y if x==y. [1] NetBSD fix for this: https://github.com/IIJ-NetBSD/netbsd-src/commit/3bc685224189d2b7dfb68da52d9725a256a667bd [2] glibc fix for this: https://github.com/bminor/glibc/commit/bc9f6000f6752153e5e1902259d5f491a88a1ae5#diff-bcc0628a39c3c2003047dcb5a40a8b50c00f01a74b1c8c1100d770a8e48b1ce2 [3] Linux man page: https://man7.org/linux/man-pages/man3/nextafter.3.html (cherry picked from commit 7ccfe49e8ce908c581f82c8dbf0f9064df488a24) --- newlib/libm/common/s_nextafter.c | 2 +- newlib/libm/common/sf_nextafter.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/newlib/libm/common/s_nextafter.c b/newlib/libm/common/s_nextafter.c index 9453a0a001..356c79f3de 100644 --- a/newlib/libm/common/s_nextafter.c +++ b/newlib/libm/common/s_nextafter.c @@ -70,7 +70,7 @@ PORTABILITY if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) || /* x is nan */ ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0)) /* y is nan */ return x+y; - if(x==y) return x; /* x=y, return x */ + if(x==y) return y; /* x=y, return y */ if((ix|lx)==0) { /* x == 0 */ INSERT_WORDS(x,hy&0x80000000,1); /* return +-minsubnormal */ y = x*x; diff --git a/newlib/libm/common/sf_nextafter.c b/newlib/libm/common/sf_nextafter.c index cea4da58dd..cdc7c663df 100644 --- a/newlib/libm/common/sf_nextafter.c +++ b/newlib/libm/common/sf_nextafter.c @@ -32,7 +32,7 @@ if(FLT_UWORD_IS_NAN(ix) || FLT_UWORD_IS_NAN(iy)) return x+y; - if(x==y) return x; /* x=y, return x */ + if(x==y) return y; /* x=y, return y */ if(FLT_UWORD_IS_ZERO(ix)) { /* x == 0 */ SET_FLOAT_WORD(x,(hy&0x80000000)|FLT_UWORD_MIN); y = x*x; From a951054d992dbd379c2336101515fd9e8ad8a882 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Mon, 25 Nov 2024 19:51:53 +0900 Subject: [PATCH 035/116] Cygwin: signal: Fix deadlock between main thread and sig thread Previously, a deadlock happened if many SIGSTOP/SIGCONT signals were received rapidly. If the main thread sends __SIGFLUSH at the timing when SIGSTOP is handled by the sig thread, but not is handled by the main thread yet (sig_handle_tty_stop() not called yet), and if SIGCONT is received, the sig thread waits for cygtls::current_sig (is SIGSTOP now) cleared. However, the main thread waits for the pack.wakeup using WaitForSingleObject(), so the main thread cannot handle SIGSTOP. This is the mechanism of the deadlock. This patch uses cygwait() instead of WaitForSingleObject() to be able to handle the pending SIGSTOP. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: 7759daa979c4 ("(sig_send): Fill out sigpacket structure to send to signal thread rather than racily sending separate packets.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit d243e51ef1d30312ba1e21b4d25a1ca9a8dc1f63) --- winsup/cygwin/sigproc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index a758bc8f2c..2e813b3a7e 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -760,7 +760,7 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls) if (wait_for_completion) { sigproc_printf ("Waiting for pack.wakeup %p", pack.wakeup); - rc = WaitForSingleObject (pack.wakeup, WSSC); + rc = cygwait (pack.wakeup, WSSC); ForceCloseHandle (pack.wakeup); } else From 09be373e4594345e65ef966122a85fc35a35cef3 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Mon, 25 Nov 2024 20:19:06 +0900 Subject: [PATCH 036/116] Cygwin: signal: Handle queued signal without explicit __SIGFLUSH With the previous code, the queued signal is tried to resend only when a new signal arrives or pending_signals::pending() is called. With this patch, if the signal is queued and the retry flag is not set and the new signal is not received yet, the sig thread tries to handle the queued signal again. Without this patch, the chance to handle the queue would be delayed. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: 5e31c80e4e8d ("(pending_signals::pending): Force an additional loop through wait_sig by setting retry whenever this function is called.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit e10f822a2b39bade20858ba3c704a8bb7d965cb4) --- winsup/cygwin/sigproc.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 2e813b3a7e..ecf79bc712 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -1321,6 +1321,9 @@ wait_sig (VOID *) sigpacket pack = {}; if (sigq.retry) pack.si.si_signo = __SIGFLUSH; + else if (sigq.start.next + && PeekNamedPipe (my_readsig, NULL, 0, NULL, &nb, NULL) && !nb) + pack.si.si_signo = __SIGFLUSH; else if (!ReadFile (my_readsig, &pack, sizeof (pack), &nb, NULL)) Sleep (INFINITE); /* Assume were exiting. Never exit this thread */ else if (nb != sizeof (pack) || !pack.si.si_signo) From e1b6996e7bfacac3f0b93bbf9f1c40a7c734eeb3 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Mon, 25 Nov 2024 20:55:44 +0900 Subject: [PATCH 037/116] Cygwin: signal: Drop unnecessary queue flush Previously, the retry flag was always set when pending_signal::pending() was called. However, if the queue is empty sig thread tries to flush the queue even though it is not necessary. With this patch, the retry flag is set only if the queue is not empty. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: 5e31c80e4e8d ("(pending_signals::pending): Force an additional loop through wait_sig by setting retry whenever this function is called.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit 57ce5f1e0bf4a6fef7173b2549edc4f2090dd0e7) --- winsup/cygwin/sigproc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index ecf79bc712..618cc45565 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -110,7 +110,7 @@ class pending_signals public: void add (sigpacket&); - bool pending () {retry = true; return !!start.next;} + bool pending () {retry = !!start.next; return retry;} void clear (int sig) {sigs[sig].si.si_signo = 0;} void clear (_cygtls *tls); friend void sig_dispatch_pending (bool); From f930a973bd98dfa2ade96e2ae2c4e39554a80f5f Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Wed, 27 Nov 2024 20:03:55 +0900 Subject: [PATCH 038/116] Cygwin: signal: Fix another deadlock between main and sig thread In _cygtls::handle_SIGCONT(), the sig thread waits for the main thread to process the signal without unlocking the TLS area. This causes a deadlock if the main thread tries to acquire a lock for the TLS area in the meantime. With this patch, unlock the TLS before calling yield() in handle_SIGCONT(). Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: 26158dc3e9c2("* exceptions.cc (sigpacket::process): Lock _cygtls area of thread before accessing it.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit 9ae51bcc51a7901559c476e6301597760c2726fd) --- winsup/cygwin/exceptions.cc | 10 +++++++--- winsup/cygwin/local_includes/cygtls.h | 4 +++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 60c1f594f8..42556093ad 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -1419,7 +1419,7 @@ api_fatal_debug () /* Attempt to carefully handle SIGCONT when we are stopped. */ void -_cygtls::handle_SIGCONT () +_cygtls::handle_SIGCONT (threadlist_t * &tl_entry) { if (NOTSTATE (myself, PID_STOPPED)) return; @@ -1434,7 +1434,11 @@ _cygtls::handle_SIGCONT () while (1) if (sig) /* Assume that it's ok to just test sig outside of a lock since setup_handler does it this way. */ - yield (); /* Attempt to schedule another thread. */ + { + cygheap->unlock_tls (tl_entry); + yield (); /* Attempt to schedule another thread. */ + tl_entry = cygheap->find_tls (_main_tls); + } else if (sigsent) break; /* SIGCONT has been recognized by other thread */ else @@ -1476,7 +1480,7 @@ sigpacket::process () if (si.si_signo == SIGCONT) { tl_entry = cygheap->find_tls (_main_tls); - _main_tls->handle_SIGCONT (); + _main_tls->handle_SIGCONT (tl_entry); cygheap->unlock_tls (tl_entry); } diff --git a/winsup/cygwin/local_includes/cygtls.h b/winsup/cygwin/local_includes/cygtls.h index f67e9136c3..f967bb9cc2 100644 --- a/winsup/cygwin/local_includes/cygtls.h +++ b/winsup/cygwin/local_includes/cygtls.h @@ -159,6 +159,8 @@ extern "C" int __ljfault (jmp_buf, int); typedef uintptr_t __tlsstack_t; +struct threadlist_t; + class _cygtls { public: /* Do NOT remove this public: line, it's a marker for gentls_offsets. */ @@ -262,7 +264,7 @@ class _cygtls { will_wait_for_signal = false; } - void handle_SIGCONT (); + void handle_SIGCONT (threadlist_t * &); static void cleanup_early(struct _reent *); private: void call2 (DWORD (*) (void *, void *), void *, void *); From 3a28aac4283c68e96b86ecc3a573b1e7df60dde6 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Sat, 23 Nov 2024 11:25:56 +0100 Subject: [PATCH 039/116] Cygwin: gendef: unify comments in terms of acquiring/releasing stacklock Various forms of describing what we do with the stacklock are used. Try to be consistent. Signed-off-by: Corinna Vinschen (cherry picked from commit 63804a28b330ccda7e1ef1c04d2d1c5e22a8e40d) --- winsup/cygwin/scripts/gendef | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/winsup/cygwin/scripts/gendef b/winsup/cygwin/scripts/gendef index c2ad5c75e3..fae7a7f313 100755 --- a/winsup/cygwin/scripts/gendef +++ b/winsup/cygwin/scripts/gendef @@ -132,8 +132,8 @@ _sigfe_maybe: # stack is aligned on entry! _sigfe: # stack is aligned on entry! .seh_endprologue movq %gs:8,%r10 # location of bottom of stack -1: movl \$1,%r11d # potential lock value - xchgl %r11d,_cygtls.stacklock(%r10) # see if we can grab it +1: movl \$1,%r11d + xchgl %r11d,_cygtls.stacklock(%r10) # try to acquire lock movl %r11d,_cygtls.spinning(%r10) # flag if we are waiting for lock testl %r11d,%r11d # it will be zero jz 2f # if so @@ -145,7 +145,7 @@ _sigfe: # stack is aligned on entry! xchgq %r11,8(%rsp) # exchange with real return value movq %r11,(%rax) # store real return value on alt stack incl _cygtls.incyg(%r10) - decl _cygtls.stacklock(%r10) # remove lock + decl _cygtls.stacklock(%r10) # release lock popq %rax # pop real function address from stack jmp *%rax # and jmp to it .seh_endproc @@ -156,8 +156,8 @@ _sigbe: # return here after cygwin syscall # stack is aligned on entry! .seh_endprologue movq %gs:8,%r10 # address of bottom of tls -1: movl \$1,%r11d # potential lock value - xchgl %r11d,_cygtls.stacklock(%r10) # see if we can grab it +1: movl \$1,%r11d + xchgl %r11d,_cygtls.stacklock(%r10) # try to acquire lock movl %r11d,_cygtls.spinning(%r10) # flag if we are waiting for lock testl %r11d,%r11d # it will be zero jz 2f # if so @@ -241,8 +241,8 @@ sigdelayed: addq %r12,%rcx # and store as first arg to method call _ZN7_cygtls19call_signal_handlerEv # call handler -1: movl \$1,%r11d # potential lock value - xchgl %r11d,_cygtls.stacklock(%r12) # see if we can grab it +1: movl \$1,%r11d + xchgl %r11d,_cygtls.stacklock(%r12) # try to acquire lock movl %r11d,_cygtls.spinning(%r12) # flag if we are waiting for lock testl %r11d,%r11d # it will be zero jz 2f # if so @@ -258,7 +258,7 @@ sigdelayed: xchgq %r10,-8(%r11) # get return address from signal stack xorl %r11d,%r11d movl %r11d,_cygtls.incyg(%r12) - movl %r11d,_cygtls.stacklock(%r12) # unlock + movl %r11d,_cygtls.stacklock(%r12) # release lock movdqa 0x20(%rsp),%xmm0 movdqa 0x30(%rsp),%xmm1 movdqa 0x40(%rsp),%xmm2 @@ -321,7 +321,7 @@ _ZN7_cygtls4lockEv: .seh_endprologue movq %rcx,%r12 1: movl \$1,%r11d - xchgl %r11d,_cygtls.stacklock_p(%r12) + xchgl %r11d,_cygtls.stacklock_p(%r12) # try to acquire lock testl %r11d,%r11d jz 2f pause @@ -335,7 +335,7 @@ _ZN7_cygtls4lockEv: .seh_proc _ZN7_cygtls6unlockEv _ZN7_cygtls6unlockEv: .seh_endprologue - decl _cygtls.stacklock_p(%rcx) + decl _cygtls.stacklock_p(%rcx) # release lock ret .seh_endproc @@ -357,7 +357,7 @@ stabilize_sig_stack: .seh_endprologue movq %gs:8,%r12 1: movl \$1,%r10d - xchgl %r10d,_cygtls.stacklock(%r12) + xchgl %r10d,_cygtls.stacklock(%r12) # try to acquire lock movl %r10d,_cygtls.spinning(%r12) # flag if we are waiting for lock testl %r10d,%r10d jz 2f @@ -366,7 +366,7 @@ stabilize_sig_stack: 2: incl _cygtls.incyg(%r12) cmpl \$0,_cygtls.sig(%r12) jz 3f - decl _cygtls.stacklock(%r12) # unlock + decl _cygtls.stacklock(%r12) # release lock movq \$_cygtls.start_offset,%rcx # point to beginning addq %r12,%rcx # of tls block call _ZN7_cygtls19call_signal_handlerEv @@ -443,7 +443,7 @@ setjmp: popq %rcx movq _cygtls.stackptr(%r11),%r10 movq %r10,(%rcx) - decl _cygtls.stacklock(%r11) + decl _cygtls.stacklock(%r11) # release lock xorl %eax,%eax ret .seh_endproc @@ -480,7 +480,7 @@ longjmp: movl %r12d,%eax # restore return value movq (%rcx),%r10 # get old signal stack movq %r10,_cygtls.stackptr(%r11) # restore - decl _cygtls.stacklock(%r11) # relinquish lock + decl _cygtls.stacklock(%r11) # release lock xorl %r10d,%r10d movl %r10d,_cygtls.incyg(%r11) # we're not in cygwin anymore movq 0x8(%rcx),%rbx From da6d5f838c19aeaacbda85b6fe3f27c022d12f1c Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Fri, 29 Nov 2024 17:08:46 +0900 Subject: [PATCH 040/116] Cygwin: cygtls: Prompt system to switch tasks explicitly in lock() This patch calls Sleep(0) in the wait loop in lock() to increase the chance of being unlocked in other threads. The lock(), unlock() and locked() are moved from sigfe.s to cygtls.h so that allows inline expansion. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: 61522196c715 ("* Merge in cygwin-64bit-branch.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit 9b7a84d24aa17bdd727eb402cc544fa36f4d812e) --- winsup/cygwin/local_includes/cygtls.h | 19 +++++++++++--- winsup/cygwin/scripts/gendef | 36 --------------------------- 2 files changed, 15 insertions(+), 40 deletions(-) diff --git a/winsup/cygwin/local_includes/cygtls.h b/winsup/cygwin/local_includes/cygtls.h index f967bb9cc2..23ef1701a5 100644 --- a/winsup/cygwin/local_includes/cygtls.h +++ b/winsup/cygwin/local_includes/cygtls.h @@ -197,7 +197,7 @@ class _cygtls int sig; unsigned incyg; unsigned spinning; - unsigned stacklock; + volatile unsigned stacklock; __tlsstack_t *stackptr; __tlsstack_t stack[TLS_STACK_SIZE]; unsigned initialized; @@ -225,9 +225,20 @@ class _cygtls int call_signal_handler (); void remove_wq (DWORD); void fixup_after_fork (); - void lock (); - void unlock (); - bool locked (); + void lock () + { + while (InterlockedExchange (&stacklock, 1)) + { +#ifdef __x86_64__ + __asm__ ("pause"); +#else +#error unimplemented for this target +#endif + Sleep (0); + } + } + void unlock () { stacklock = 0; } + bool locked () { return !!stacklock; } HANDLE get_signal_arrived (bool wait_for_lock = true) { if (!signal_arrived) diff --git a/winsup/cygwin/scripts/gendef b/winsup/cygwin/scripts/gendef index fae7a7f313..bb87ab55e5 100755 --- a/winsup/cygwin/scripts/gendef +++ b/winsup/cygwin/scripts/gendef @@ -312,42 +312,6 @@ _ZN7_cygtls3popEv: ret .seh_endproc -# _cygtls::lock - .global _ZN7_cygtls4lockEv - .seh_proc _ZN7_cygtls4lockEv -_ZN7_cygtls4lockEv: - pushq %r12 - .seh_pushreg %r12 - .seh_endprologue - movq %rcx,%r12 -1: movl \$1,%r11d - xchgl %r11d,_cygtls.stacklock_p(%r12) # try to acquire lock - testl %r11d,%r11d - jz 2f - pause - jmp 1b -2: popq %r12 - ret - .seh_endproc - -# _cygtls::unlock - .global _ZN7_cygtls6unlockEv - .seh_proc _ZN7_cygtls6unlockEv -_ZN7_cygtls6unlockEv: - .seh_endprologue - decl _cygtls.stacklock_p(%rcx) # release lock - ret - .seh_endproc - -# _cygtls::locked - .global _ZN7_cygtls6lockedEv - .seh_proc _ZN7_cygtls6lockedEv -_ZN7_cygtls6lockedEv: - .seh_endprologue - movl _cygtls.stacklock_p(%rcx),%eax - ret - .seh_endproc - .seh_proc stabilize_sig_stack stabilize_sig_stack: pushq %r12 From 8fa1c02625c9c962690291fc6dcd6685ed110544 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Fri, 29 Nov 2024 17:13:32 +0900 Subject: [PATCH 041/116] Cygwin: signal: Fix a short period of deadlock The main thread waits for the sig thread to read the signal pipe by calling Sleep(10) if writing to the signal pipe has failed. However, if the signal thread waiting for another signal being handled in the main thread, the sig thread does not read the signal pipe. To avoid such a situation, this patch replaces Sleep(10) to cygwait(). Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: 6f05b327678f ("(sig_send): Retry WriteFiles which fail when there is no error but packbytes have not been sent.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit 2544e753963e9c15a9e3fe35188d8dea7b39d748) --- winsup/cygwin/sigproc.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 618cc45565..601147ff6c 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -727,7 +727,8 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls) res = WriteFile (sendsig, leader, packsize, &nb, NULL); if (!res || packsize == nb) break; - Sleep (10); + if (cygwait (NULL, 10, cw_sig_eintr) == WAIT_SIGNALED) + _my_tls.call_signal_handler (); res = 0; } From e9fdf6f420090a800f3e41dd730d53c0cf5b5f8b Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Fri, 29 Nov 2024 16:58:05 +0900 Subject: [PATCH 042/116] Cygwin: signal: Optimize the priority of the sig thread Previously, the sig thread ran in THREAD_PRIORITY_HIGHEST priority. This causes a critical delay in the signal handling in the main thread if too many signals are received rapidly and the CPU is very busy. In this case, most of the CPU time is allocated to the sig thread, so the main thread cannot have a chance of handling signals. With this patch, to avoid such a situation, the priority of the sig thread is set to THREAD_PRIORITY_NORMAL priority. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: 53ad6f1394aa ("(cygthread::cygthread): Use three only arguments for detached threads, and start the thread via QueueUserAPC/async_create.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit 9a274a967d1fe9a28d0d658749b08e65d09d3ee0) --- winsup/cygwin/sigproc.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 601147ff6c..3fe6447e54 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -1316,6 +1316,7 @@ wait_sig (VOID *) hntdll = GetModuleHandle ("ntdll.dll"); + SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_NORMAL); for (;;) { DWORD nb; From 7adfc92401cb00b9a59b25a792a5d5f6dc1220a6 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Tue, 3 Dec 2024 22:14:44 +0900 Subject: [PATCH 043/116] Cygwin: signal: Increase chance of handling signal in main thread If the process() fails and the signal remains in the queue, the most possible reason is that the target thread is already armed by another signal and does not handle it yet. With this patch, to increase the chance of handling it in the other threads, call yield() before retrying process(). Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: e10f822a2b39 ("Cygwin: signal: Handle queued signal without explicit __SIGFLUSH") Reported-by: Christian Franke Reviewed-by: Signed-off-by: Takashi Yano (cherry picked from commit c48d58d838d90df6247123c487686699742d75de) --- winsup/cygwin/sigproc.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 3fe6447e54..b9669a8616 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -1325,7 +1325,10 @@ wait_sig (VOID *) pack.si.si_signo = __SIGFLUSH; else if (sigq.start.next && PeekNamedPipe (my_readsig, NULL, 0, NULL, &nb, NULL) && !nb) - pack.si.si_signo = __SIGFLUSH; + { + yield (); + pack.si.si_signo = __SIGFLUSH; + } else if (!ReadFile (my_readsig, &pack, sizeof (pack), &nb, NULL)) Sleep (INFINITE); /* Assume were exiting. Never exit this thread */ else if (nb != sizeof (pack) || !pack.si.si_signo) From 60fa8d793f867d896b824c66789c48e86dec4ea7 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 4 Dec 2024 13:50:17 +0100 Subject: [PATCH 044/116] Cygwin: setjmp/longjmp: decrement incyg after signal handling Commit 0b6fbd396ca2f ("* exceptions.cc (_cygtls::interrupt_now): Revert to checking for "spinning" when choosing to defer signal.") introduced a bug in the loop inside the stabilize_sig_stack subroutine: First, stabilize_sig_stack grabs the stacklock. The _cygtls::incyg flag is then incremented before checking if a signal has to be handled for the current thread. If no signal waits, the code simply jumps out, decrements _cygtls::incyg and returns to the caller, which eventually releases the stacklock. However, if a signal is waiting, stabilize_sig_stack releases the stacklock, calls _cygtls::call_signal_handler(), and returns to the start of the subroutine, trying to grab the lock. After grabbing the lock, it increments _cygtls::incyg... wait... again? The loop does not decrement _cygtls::incyg after _cygtls::call_signal_handler(), which returns with _cygtls::incyg set to 1. So it increments incyg to 2. If no other signal is waiting, stabilize_sig_stack jumps out and decrements _cygtls::incyg to 1. Eventually, setjmp or longjmp both will return to user code with _cygtls::incyg set to 1. This *may* be fixed at some later point when signals arrive, but there will be a time when the application runs in user code with broken signal handling. Fixes: 0b6fbd396ca2f ("* exceptions.cc (_cygtls::interrupt_now): Revert to checking for "spinning" when choosing to defer signal.") Signed-off-by: Corinna Vinschen (cherry picked from commit 41e1013e6846f1774dfec085ff983990f67e6437) --- winsup/cygwin/scripts/gendef | 1 + 1 file changed, 1 insertion(+) diff --git a/winsup/cygwin/scripts/gendef b/winsup/cygwin/scripts/gendef index bb87ab55e5..e02d3503cc 100755 --- a/winsup/cygwin/scripts/gendef +++ b/winsup/cygwin/scripts/gendef @@ -334,6 +334,7 @@ stabilize_sig_stack: movq \$_cygtls.start_offset,%rcx # point to beginning addq %r12,%rcx # of tls block call _ZN7_cygtls19call_signal_handlerEv + decl _cygtls.incyg(%r12) jmp 1b 3: decl _cygtls.incyg(%r12) addq \$0x20,%rsp From 52d1c851fb0dfa16461d83fdfa4d70643b996edc Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Thu, 5 Dec 2024 21:15:13 +0100 Subject: [PATCH 045/116] Cygwin: cygtls: add volatile qualifier to spinning Given that spinning is only checked once at the start of a _cygtls::interrupt_now() which is called in a loop, it's probably not necessary to mark _cygtls::spinning as volatile. However, spinning is changed from assembler code and we don't want the compiler to make funny assumptions, so, better safe than sorry. Signed-off-by: Corinna Vinschen (cherry picked from commit 3a9fb7c561d9e8a78e444dd3920c57e857a92baa) --- winsup/cygwin/local_includes/cygtls.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/local_includes/cygtls.h b/winsup/cygwin/local_includes/cygtls.h index 23ef1701a5..e4e3889aff 100644 --- a/winsup/cygwin/local_includes/cygtls.h +++ b/winsup/cygwin/local_includes/cygtls.h @@ -196,7 +196,7 @@ class _cygtls waitq wq; int sig; unsigned incyg; - unsigned spinning; + volatile unsigned spinning; volatile unsigned stacklock; __tlsstack_t *stackptr; __tlsstack_t stack[TLS_STACK_SIZE]; From 9c34e029918d482eef9fb4305530cb581f42dbe6 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Thu, 5 Dec 2024 18:34:02 +0100 Subject: [PATCH 046/116] Cygwin: setjmp/longjmp: drop setting spinning flag Per the comment in _cygtls::interrupt_now(), the spinning flag is supposed to guard that the targeted thread is about to enter the Cygwin DLL. Setting spinning has then been added to _sigfe, _sigbe, sigdelayed and stabilize_sig_stack, the latter being called from setjmp/longjmp. However, setjmp/longjmp only enter the DLL in case of a pending signal, calling _cygtls::call_signal_handler(). This in turn is already guarded by setting the incyg flag, and there's no other action in stabilize_sig_stack which might interfere with the signal setup. All the rest of setjmp/longjmp is plain userspace. Therefore, drop setting the spinning flag from stabilize_sig_stack, because it results in dropped signals in tight longjmp loops. Fixes: edc4f86ad2827 ("* Makefile.in (clean): Remove sigfe.s.") Signed-off-by: Corinna Vinschen (cherry picked from commit 96d856320a1d740546eaf8a6c0ddb3d489e10492) --- winsup/cygwin/scripts/gendef | 1 - 1 file changed, 1 deletion(-) diff --git a/winsup/cygwin/scripts/gendef b/winsup/cygwin/scripts/gendef index e02d3503cc..bbd5f27413 100755 --- a/winsup/cygwin/scripts/gendef +++ b/winsup/cygwin/scripts/gendef @@ -322,7 +322,6 @@ stabilize_sig_stack: movq %gs:8,%r12 1: movl \$1,%r10d xchgl %r10d,_cygtls.stacklock(%r12) # try to acquire lock - movl %r10d,_cygtls.spinning(%r12) # flag if we are waiting for lock testl %r10d,%r10d jz 2f pause From 2f9258b1c585b910c9d837af3d33f54e71e17ae2 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Thu, 5 Dec 2024 22:28:19 +0100 Subject: [PATCH 047/116] Cygwin: Add setjmp/longjmp fix to 3.5.5 release messages Signed-off-by: Corinna Vinschen (cherry picked from commit f71550e0dbef51e0a4a706edae49c33c5372db19) --- winsup/cygwin/release/3.5.5 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index d5063af164..7eece3bbdb 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -54,3 +54,6 @@ Fixes: - Fix using invalid chars in temporary file names for deleted files. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256813.html + +- Fix losing signals during setjmp/longjmp. + Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256808.html From 5bd4f9936f20ef5f06dc11986271744bf6d87359 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Fri, 29 Nov 2024 16:46:48 +0900 Subject: [PATCH 048/116] Cygwin: signal: Remove queue entry from the queue chain when cleared The queue is cleaned up by removing the entries having si_signo == 0 while processing the queued signals, however, sigpacket::process() may set si_signo in the queue to 0 of the entry already processed but not succeed by calling sig_clear(). This patch ensures the sig_clear() to remove the entry from the queue chain. For this purpose, the pointer prev has been added to the sigpacket. This is to handle the following case appropriately. Consider the queued signal chain of: A->B->C->D without pointer prev. Assume that the pointer 'q' and 'qnext' point to C, and process() is processing C. If B is cleared in process(), A->next should be set to to C in sigpacket::clear(). Then, if process() for C succeeds, C should be removed from the queue, so A->next should be set to D. However, we cannot do that because we do not have the pointer to A in the while loop in wait_sig(). With the pointer prev, we can easily access A and C in sigpacket::clear() as well as A and D in the while loop in wait_sig() using the pointer prev and next without pursuing the chain. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: 9d2155089e87 ("(wait_sig): Define variable q to be the start of the signal queue. Just iterate through sigq queue, deleting processed or zeroed signals") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit d565aca46f06117ef16ec37c51767a5e140ee9e2) --- winsup/cygwin/local_includes/sigproc.h | 3 +- winsup/cygwin/sigproc.cc | 48 +++++++++++++++++--------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/winsup/cygwin/local_includes/sigproc.h b/winsup/cygwin/local_includes/sigproc.h index 7aca80595d..41745f214c 100644 --- a/winsup/cygwin/local_includes/sigproc.h +++ b/winsup/cygwin/local_includes/sigproc.h @@ -51,8 +51,9 @@ struct sigpacket { HANDLE wakeup; HANDLE thread_handle; - struct sigpacket *next; }; + struct sigpacket *next; + struct sigpacket *prev; int process (); int setup_handler (void *, struct sigaction&, _cygtls *); }; diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index b9669a8616..287e78ff52 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -111,7 +111,7 @@ class pending_signals public: void add (sigpacket&); bool pending () {retry = !!start.next; return retry;} - void clear (int sig) {sigs[sig].si.si_signo = 0;} + void clear (int sig); void clear (_cygtls *tls); friend void sig_dispatch_pending (bool); friend void wait_sig (VOID *arg); @@ -432,21 +432,35 @@ sig_clear (int sig) sigq.clear (sig); } +/* Clear pending signals of specific si_signo. + Called from sigpacket::process(). */ +void +pending_signals::clear (int sig) +{ + sigpacket *q = sigs + sig; + if (!sig || !q->si.si_signo) + return; + q->si.si_signo = 0; + q->prev->next = q->next; + if (q->next) + q->next->prev = q->prev; +} + /* Clear pending signals of specific thread. Called under TLS lock from _cygtls::remove_pending_sigs. */ void pending_signals::clear (_cygtls *tls) { - sigpacket *q = &start, *qnext; + sigpacket *q = &start; - while ((qnext = q->next)) - if (qnext->sigtls == tls) + while ((q = q->next)) + if (q->sigtls == tls) { - qnext->si.si_signo = 0; - q->next = qnext->next; + q->si.si_signo = 0; + q->prev->next = q->next; + if (q->next) + q->next->prev = q->prev; } - else - q = qnext; } /* Clear pending signals of specific thread. Called from _cygtls::remove */ @@ -1300,7 +1314,10 @@ pending_signals::add (sigpacket& pack) return; *se = pack; se->next = start.next; - start.next = se; + se->prev = &start; + se->prev->next = se; + if (se->next) + se->next->prev = se; } /* Process signals by waiting for signal data to arrive in a pipe. @@ -1455,17 +1472,16 @@ wait_sig (VOID *) case __SIGFLUSHFAST: if (!sig_held) { - sigpacket *qnext; /* Check the queue for signals. There will always be at least one thing on the queue if this was a valid signal. */ - while ((qnext = q->next)) + while ((q = q->next)) { - if (qnext->si.si_signo && qnext->process () <= 0) - q = qnext; - else + if (q->si.si_signo && q->process () > 0) { - q->next = qnext->next; - qnext->si.si_signo = 0; + q->si.si_signo = 0; + q->prev->next = q->next; + if (q->next) + q->next->prev = q->prev; } } /* At least one signal still queued? The event is used in select From b38ba4b9af354de8520ed0e44286a4e0431ccdc3 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Wed, 4 Dec 2024 11:53:41 +0900 Subject: [PATCH 049/116] Cygwin: signal: Introduce a lock for the signal queue Currently, the signal queue is touched by the thread sig as well as other threads that call sigaction_worker(). This potentially has a possibility to destroy the signal queue chain. A possible worst result may be a self-loop chain which causes infinite loop. With this patch, lock()/unlock() are introduce to avoid such a situation. Fixes: 474048c26edf ("* sigproc.cc (pending_signals::add): Just index directly into signal array rather than treating the array as a heap.") Suggested-by: Corinna Vinschen Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit 496fa7b2ce0052550eab8900723ebb59c33d25e7) --- winsup/cygwin/exceptions.cc | 12 +++++------ winsup/cygwin/local_includes/sigproc.h | 2 +- winsup/cygwin/signal.cc | 4 ++-- winsup/cygwin/sigproc.cc | 28 +++++++++++++++++++++----- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 42556093ad..a560a3f344 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -1448,10 +1448,10 @@ _cygtls::handle_SIGCONT (threadlist_t * &tl_entry) sigsent = true; } /* Clear pending stop signals */ - sig_clear (SIGSTOP); - sig_clear (SIGTSTP); - sig_clear (SIGTTIN); - sig_clear (SIGTTOU); + sig_clear (SIGSTOP, false); + sig_clear (SIGTSTP, false); + sig_clear (SIGTTIN, false); + sig_clear (SIGTTOU, false); } int @@ -1552,14 +1552,14 @@ sigpacket::process () goto exit_sig; if (si.si_signo == SIGSTOP) { - sig_clear (SIGCONT); + sig_clear (SIGCONT, false); goto stop; } /* Clear pending SIGCONT on stop signals */ if (si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU) - sig_clear (SIGCONT); + sig_clear (SIGCONT, false); if (handler == (void *) SIG_DFL) { diff --git a/winsup/cygwin/local_includes/sigproc.h b/winsup/cygwin/local_includes/sigproc.h index 41745f214c..7573aa14c5 100644 --- a/winsup/cygwin/local_includes/sigproc.h +++ b/winsup/cygwin/local_includes/sigproc.h @@ -63,7 +63,7 @@ void set_signal_mask (sigset_t&, sigset_t); int handle_sigprocmask (int sig, const sigset_t *set, sigset_t *oldset, sigset_t& opmask); -void sig_clear (int); +void sig_clear (int, bool); void sig_set_pending (int); int handle_sigsuspend (sigset_t); diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index 9ee6cf9959..fb4983b573 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -451,9 +451,9 @@ sigaction_worker (int sig, const struct sigaction *newact, if (!(gs.sa_flags & SA_NODEFER)) gs.sa_mask |= SIGTOMASK(sig); if (gs.sa_handler == SIG_IGN) - sig_clear (sig); + sig_clear (sig, true); if (gs.sa_handler == SIG_DFL && sig == SIGCHLD) - sig_clear (sig); + sig_clear (sig, true); if (sig == SIGCHLD) { myself->process_state &= ~PID_NOCLDSTOP; diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 287e78ff52..1ab33fc3c2 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -106,12 +106,16 @@ class pending_signals { sigpacket sigs[_NSIG + 1]; sigpacket start; + SRWLOCK queue_lock; bool retry; + void lock () { AcquireSRWLockExclusive (&queue_lock); } + void unlock () { ReleaseSRWLockExclusive (&queue_lock); } public: + pending_signals (): queue_lock (SRWLOCK_INIT) {} void add (sigpacket&); bool pending () {retry = !!start.next; return retry;} - void clear (int sig); + void clear (int sig, bool need_lock); void clear (_cygtls *tls); friend void sig_dispatch_pending (bool); friend void wait_sig (VOID *arg); @@ -427,23 +431,27 @@ proc_terminate () /* Clear pending signal */ void -sig_clear (int sig) +sig_clear (int sig, bool need_lock) { - sigq.clear (sig); + sigq.clear (sig, need_lock); } /* Clear pending signals of specific si_signo. Called from sigpacket::process(). */ void -pending_signals::clear (int sig) +pending_signals::clear (int sig, bool need_lock) { sigpacket *q = sigs + sig; if (!sig || !q->si.si_signo) return; + if (need_lock) + lock (); q->si.si_signo = 0; q->prev->next = q->next; if (q->next) q->next->prev = q->prev; + if (need_lock) + unlock (); } /* Clear pending signals of specific thread. Called under TLS lock from @@ -453,6 +461,7 @@ pending_signals::clear (_cygtls *tls) { sigpacket *q = &start; + lock (); while ((q = q->next)) if (q->sigtls == tls) { @@ -461,6 +470,7 @@ pending_signals::clear (_cygtls *tls) if (q->next) q->next->prev = q->prev; } + unlock (); } /* Clear pending signals of specific thread. Called from _cygtls::remove */ @@ -1313,11 +1323,13 @@ pending_signals::add (sigpacket& pack) if (se->si.si_signo) return; *se = pack; + lock (); se->next = start.next; se->prev = &start; se->prev->next = se; if (se->next) se->next->prev = se; + unlock (); } /* Process signals by waiting for signal data to arrive in a pipe. @@ -1398,6 +1410,7 @@ wait_sig (VOID *) bool issig_wait; *pack.mask = 0; + sigq.lock (); while ((q = q->next)) { _cygtls *sigtls = q->sigtls ?: _main_tls; @@ -1411,6 +1424,7 @@ wait_sig (VOID *) } } } + sigq.unlock (); } break; case __SIGPENDING: @@ -1419,6 +1433,7 @@ wait_sig (VOID *) *pack.mask = 0; tl_entry = cygheap->find_tls (pack.sigtls); + sigq.lock (); while ((q = q->next)) { /* Skip thread-specific signals for other threads. */ @@ -1427,6 +1442,7 @@ wait_sig (VOID *) if (pack.sigtls->sigmask & (bit = SIGTOMASK (q->si.si_signo))) *pack.mask |= bit; } + sigq.unlock (); cygheap->unlock_tls (tl_entry); } break; @@ -1461,7 +1477,7 @@ wait_sig (VOID *) break; default: /* Normal (positive) signal */ if (pack.si.si_signo < 0) - sig_clear (-pack.si.si_signo); + sig_clear (-pack.si.si_signo, true); else sigq.add (pack); fallthrough; @@ -1474,6 +1490,7 @@ wait_sig (VOID *) { /* Check the queue for signals. There will always be at least one thing on the queue if this was a valid signal. */ + sigq.lock (); while ((q = q->next)) { if (q->si.si_signo && q->process () > 0) @@ -1484,6 +1501,7 @@ wait_sig (VOID *) q->next->prev = q->prev; } } + sigq.unlock (); /* At least one signal still queued? The event is used in select only, and only to decide if WFMO should wake up in case a signalfd is waiting via select/poll for being ready to read a From db55d548e395c5b9979b9842a2148a390968fb32 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Tue, 26 Nov 2024 13:56:51 +0900 Subject: [PATCH 050/116] Cygwin: Document several fixes for signal handling in release note (cherry picked from commit cfadd852aa5787eb29403efc75bfa637028bfd40) --- winsup/cygwin/release/3.5.5 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index 7eece3bbdb..e99739241c 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -57,3 +57,7 @@ Fixes: - Fix losing signals during setjmp/longjmp. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256808.html + +- Fix several problems triggered when a lot of SIGSTOP/SIGCONT signals + are received rapidly. + Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html From dac9ad1e0d3de1c844c79c18d3c29d1d5f2059ec Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Tue, 10 Dec 2024 13:55:54 +0100 Subject: [PATCH 051/116] Cygwin: path_conv: allow NULL handle in init_reopen_attr() init_reopen_attr() doesn't guard against a NULL handle. However, there are scenarios calling functions deliberately with a NULL handle, for instance, av::setup() calling check_file_access() only if opening the file did NOT succeed. So check for a NULL handle in init_reopen_attr() and if so, use the name based approach filling the OBJECT_ATTRIBUTES struct, just as in the has_buggy_reopen() case. Fixes: 4c9d01fdad2a ("* mount.h (class fs_info): Add has_buggy_reopen flag and accessor methods.") Signed-off-by: Corinna Vinschen (cherry picked from commit 815eba882e32ecadd6862c71c36fccdcb0842a76) --- winsup/cygwin/local_includes/path.h | 2 +- winsup/cygwin/sec/base.cc | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/winsup/cygwin/local_includes/path.h b/winsup/cygwin/local_includes/path.h index cd0cc8a412..5f5cf5cb5b 100644 --- a/winsup/cygwin/local_includes/path.h +++ b/winsup/cygwin/local_includes/path.h @@ -316,7 +316,7 @@ class path_conv } inline POBJECT_ATTRIBUTES init_reopen_attr (OBJECT_ATTRIBUTES &attr, HANDLE h) { - if (has_buggy_reopen ()) + if (!h || has_buggy_reopen ()) InitializeObjectAttributes (&attr, get_nt_native_path (), objcaseinsensitive (), NULL, NULL) else diff --git a/winsup/cygwin/sec/base.cc b/winsup/cygwin/sec/base.cc index 0fc8699bfc..14606242d8 100644 --- a/winsup/cygwin/sec/base.cc +++ b/winsup/cygwin/sec/base.cc @@ -62,8 +62,7 @@ get_file_sd (HANDLE fh, path_conv &pc, security_descriptor &sd, if (!fh || !NT_SUCCESS (status)) { status = NtOpenFile (&fh, READ_CONTROL, - fh ? pc.init_reopen_attr (attr, fh) - : pc.get_object_attr (attr, sec_none_nih), + pc.init_reopen_attr (attr, fh), &io, FILE_SHARE_VALID_FLAGS, FILE_OPEN_NO_RECALL | FILE_OPEN_FOR_BACKUP_INTENT @@ -232,9 +231,7 @@ set_file_sd (HANDLE fh, path_conv &pc, security_descriptor &sd, bool is_chown) OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK io; status = NtOpenFile (&fh, (is_chown ? WRITE_OWNER : 0) | WRITE_DAC, - fh ? pc.init_reopen_attr (attr, fh) - : pc.get_object_attr (attr, sec_none_nih), - &io, + pc.init_reopen_attr (attr, fh), &io, FILE_SHARE_VALID_FLAGS, FILE_OPEN_NO_RECALL | FILE_OPEN_FOR_BACKUP_INTENT From 837e596f4232228bacf11386a5408a9773b7d2f1 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Sun, 8 Dec 2024 07:34:48 +0900 Subject: [PATCH 052/116] Cygwin: access: Correction for samba/SMB share Previously, access() and eaccess() does not determine the permissions for files on samba/SMB share correctly. Even if the user logs-in as the owner of the file, access() and eaccess() referes to others' permissions. With this patch, to determine the permissions correctly, NtOpenFile() with desired access mask is used. Fixes: cf762b08cfb0 ("* security.cc (check_file_access): Create.") Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit a0933cd17d19cca72b972a248e70210152f06808) --- winsup/cygwin/sec/base.cc | 119 +++++++------------------------------- 1 file changed, 20 insertions(+), 99 deletions(-) diff --git a/winsup/cygwin/sec/base.cc b/winsup/cygwin/sec/base.cc index 14606242d8..2e50ce0c38 100644 --- a/winsup/cygwin/sec/base.cc +++ b/winsup/cygwin/sec/base.cc @@ -28,10 +28,6 @@ details. */ | GROUP_SECURITY_INFORMATION \ | OWNER_SECURITY_INFORMATION) -static GENERIC_MAPPING NO_COPY_RO file_mapping = { FILE_GENERIC_READ, - FILE_GENERIC_WRITE, - FILE_GENERIC_EXECUTE, - FILE_ALL_ACCESS }; LONG get_file_sd (HANDLE fh, path_conv &pc, security_descriptor &sd, bool justcreated) @@ -604,99 +600,9 @@ check_access (security_descriptor &sd, GENERIC_MAPPING &mapping, return ret; } -/* Samba override. Check security descriptor for Samba UNIX user and group - accounts and check if we have an RFC 2307 mapping to a Windows account. - Create a new security descriptor with all of the UNIX accounts with - valid mapping replaced with their Windows counterpart. */ -static void -convert_samba_sd (security_descriptor &sd_ret) -{ - NTSTATUS status; - BOOLEAN dummy; - PSID sid; - cygsid owner; - cygsid group; - SECURITY_DESCRIPTOR sd; - cyg_ldap cldap; - tmp_pathbuf tp; - PACL acl, oacl; - size_t acl_len; - PACCESS_ALLOWED_ACE ace; - - if (!NT_SUCCESS (RtlGetOwnerSecurityDescriptor (sd_ret, &sid, &dummy))) - return; - owner = sid; - if (!NT_SUCCESS (RtlGetGroupSecurityDescriptor (sd_ret, &sid, &dummy))) - return; - group = sid; - - if (sid_id_auth (owner) == 22) - { - struct passwd *pwd; - uid_t uid = owner.get_uid (&cldap); - if (uid < UNIX_POSIX_OFFSET && (pwd = internal_getpwuid (uid))) - owner.getfrompw (pwd); - } - if (sid_id_auth (group) == 22) - { - struct group *grp; - gid_t gid = group.get_gid (&cldap); - if (gid < UNIX_POSIX_OFFSET && (grp = internal_getgrgid (gid))) - group.getfromgr (grp); - } - - if (!NT_SUCCESS (RtlGetDaclSecurityDescriptor (sd_ret, &dummy, - &oacl, &dummy))) - return; - acl = (PACL) tp.w_get (); - RtlCreateAcl (acl, ACL_MAXIMUM_SIZE, ACL_REVISION); - acl_len = sizeof (ACL); - - for (DWORD i = 0; i < oacl->AceCount; ++i) - if (NT_SUCCESS (RtlGetAce (oacl, i, (PVOID *) &ace))) - { - cygsid ace_sid ((PSID) &ace->SidStart); - if (sid_id_auth (ace_sid) == 22) - { - if (sid_sub_auth (ace_sid, 0) == 1) /* user */ - { - struct passwd *pwd; - uid_t uid = ace_sid.get_uid (&cldap); - if (uid < UNIX_POSIX_OFFSET && (pwd = internal_getpwuid (uid))) - ace_sid.getfrompw (pwd); - } - else if (sid_sub_auth (ace_sid, 0) == 2) /* group */ - { - struct group *grp; - gid_t gid = ace_sid.get_gid (&cldap); - if (gid < UNIX_POSIX_OFFSET && (grp = internal_getgrgid (gid))) - ace_sid.getfromgr (grp); - } - } - if (!add_access_allowed_ace (acl, ace->Mask, ace_sid, acl_len, - ace->Header.AceFlags)) - return; - } - acl->AclSize = acl_len; - - RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION); - RtlSetControlSecurityDescriptor (&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED); - RtlSetOwnerSecurityDescriptor (&sd, owner, FALSE); - RtlSetGroupSecurityDescriptor (&sd, group, FALSE); - - status = RtlSetDaclSecurityDescriptor (&sd, TRUE, acl, FALSE); - if (!NT_SUCCESS (status)) - return; - DWORD sd_size = 0; - status = RtlAbsoluteToSelfRelativeSD (&sd, sd_ret, &sd_size); - if (sd_size > 0 && sd_ret.malloc (sd_size)) - RtlAbsoluteToSelfRelativeSD (&sd, sd_ret, &sd_size); -} - int check_file_access (path_conv &pc, int flags, bool effective) { - security_descriptor sd; int ret = -1; ACCESS_MASK desired = 0; if (flags & R_OK) @@ -705,13 +611,28 @@ check_file_access (path_conv &pc, int flags, bool effective) desired |= FILE_WRITE_DATA; if (flags & X_OK) desired |= FILE_EXECUTE; - if (!get_file_sd (pc.handle (), pc, sd, false)) + + if (!effective) + cygheap->user.deimpersonate (); + + OBJECT_ATTRIBUTES attr; + pc.init_reopen_attr (attr, pc.handle ()); + NTSTATUS status; + IO_STATUS_BLOCK io; + HANDLE h; + status = NtOpenFile (&h, desired, &attr, &io, FILE_SHARE_VALID_FLAGS, + FILE_OPEN_FOR_BACKUP_INTENT); + if (NT_SUCCESS (status)) { - /* Tweak Samba security descriptor as necessary. */ - if (pc.fs_is_samba ()) - convert_samba_sd (sd); - ret = check_access (sd, file_mapping, desired, flags, effective); + NtClose (h); + ret = 0; } + else + __seterrno_from_nt_status (status); + + if (!effective) + cygheap->user.reimpersonate (); + debug_printf ("flags %y, ret %d", flags, ret); return ret; } From aecd8077bfe384a4544e1774d713aff15534d8d4 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Thu, 12 Dec 2024 15:03:39 +0900 Subject: [PATCH 053/116] Cygwin: signal: Fix high load when retrying to process pending signal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The commit e10f822a2b39 has a problem that CPU load gets high if pending signal is not processed successfully for a long time. With this patch, wait_sig() calls Sleep(1), rather than yield(), if the pending signal has not been processed successfully for a predetermined time to prevent CPU from high load. Addresses: https://cygwin.com/pipermail/cygwin/2024-December/256884.html Fixes: e10f822a2b39 ("Cygwin: signal: Handle queued signal without explicit __SIGFLUSH") Reported-by: 凯夏 Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit 1d1451ccd2a6c0f0146ddee68f386061b69863c0) --- winsup/cygwin/sigproc.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 1ab33fc3c2..58a9e5a312 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -1346,6 +1346,13 @@ wait_sig (VOID *) hntdll = GetModuleHandle ("ntdll.dll"); SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_NORMAL); + + /* GetTickCount() here is enough because GetTickCount() - t0 does + not overflow until 49 days psss. Even if GetTickCount() overflows, + GetTickCount() - t0 returns correct value, since underflow in + unsigned wraps correctly. Pending a signal for more thtn 49 + days would be noncense. */ + DWORD t0 = GetTickCount (); for (;;) { DWORD nb; @@ -1355,7 +1362,7 @@ wait_sig (VOID *) else if (sigq.start.next && PeekNamedPipe (my_readsig, NULL, 0, NULL, &nb, NULL) && !nb) { - yield (); + Sleep (GetTickCount () - t0 > 10 ? 1 : 0); pack.si.si_signo = __SIGFLUSH; } else if (!ReadFile (my_readsig, &pack, sizeof (pack), &nb, NULL)) @@ -1365,6 +1372,8 @@ wait_sig (VOID *) system_printf ("garbled signal pipe data nb %u, sig %d", nb, pack.si.si_signo); continue; } + if (pack.si.si_signo != __SIGFLUSH) + t0 = GetTickCount (); sigq.retry = false; /* Don't process signals when we start exiting */ From fe598b89e856bf2a2a8e7d29a0f5525077f43f26 Mon Sep 17 00:00:00 2001 From: Ken Brown Date: Wed, 18 Dec 2024 11:39:31 -0500 Subject: [PATCH 054/116] Cygwin: mmap: fix protection when unused pages are recycled Previously, when unused pages from an mmap_record were recycled, they were given the protection of the mmap_record rather than the protection requested in the mmap call. Fix this by adding a "new_prot" parameter to mmap_list::try_map() and mmap_record::map_pages() to keep track of the requested protection. Then use new_prot in the calls to VirtualProtect(). Addresses: https://cygwin.com/pipermail/cygwin/2024-December/256911.html Fixes: f90e23f2714cb ("*autoload.cc (NtCreateSection): Define.") Signed-off-by: Ken Brown (cherry picked from commit 677e3150907a83f17e50d546f79b7ca863ebd77d) --- winsup/cygwin/mm/mmap.cc | 31 ++++++++++++++++++------------- winsup/cygwin/release/3.5.5 | 3 +++ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/winsup/cygwin/mm/mmap.cc b/winsup/cygwin/mm/mmap.cc index 332c015a72..4fec64b87d 100644 --- a/winsup/cygwin/mm/mmap.cc +++ b/winsup/cygwin/mm/mmap.cc @@ -339,8 +339,8 @@ class mmap_record SIZE_T find_unused_pages (SIZE_T pages) const; bool match (caddr_t addr, SIZE_T len, caddr_t &m_addr, SIZE_T &m_len); - off_t map_pages (SIZE_T len); - bool map_pages (caddr_t addr, SIZE_T len); + off_t map_pages (SIZE_T len, int new_prot); + bool map_pages (caddr_t addr, SIZE_T len, int new_prot); bool unmap_pages (caddr_t addr, SIZE_T len); int access (caddr_t address); @@ -373,7 +373,8 @@ class mmap_list void set (int nfd, struct stat *st); mmap_record *add_record (mmap_record &r); bool del_record (mmap_record *rec); - caddr_t try_map (void *addr, size_t len, int flags, off_t off); + caddr_t try_map (void *addr, size_t len, int new_prot, int flags, + off_t off); }; class mmap_areas @@ -455,14 +456,15 @@ mmap_record::init_page_map (mmap_record &r) } off_t -mmap_record::map_pages (SIZE_T len) +mmap_record::map_pages (SIZE_T len, int new_prot) { /* Used ONLY if this mapping matches into the chunk of another already performed mapping in a special case of MAP_ANON|MAP_PRIVATE. Otherwise it's job is now done by init_page_map(). */ DWORD old_prot; - debug_printf ("map_pages (fd=%d, len=%lu)", get_fd (), len); + debug_printf ("map_pages (fd=%d, len=%lu, new_prot=%y)", get_fd (), len, + new_prot); len = PAGE_CNT (len); off_t off = find_unused_pages (len); @@ -470,7 +472,8 @@ mmap_record::map_pages (SIZE_T len) return (off_t) 0; if (!noreserve () && !VirtualProtect (get_address () + off * wincap.page_size (), - len * wincap.page_size (), gen_protect (), + len * wincap.page_size (), + ::gen_protect (new_prot, get_flags ()), &old_prot)) { __seterrno (); @@ -483,9 +486,10 @@ mmap_record::map_pages (SIZE_T len) } bool -mmap_record::map_pages (caddr_t addr, SIZE_T len) +mmap_record::map_pages (caddr_t addr, SIZE_T len, int new_prot) { - debug_printf ("map_pages (addr=%p, len=%lu)", addr, len); + debug_printf ("map_pages (addr=%p, len=%lu, new_prot=%y)", addr, len, + new_prot); DWORD old_prot; off_t off = addr - get_address (); off /= wincap.page_size (); @@ -499,7 +503,8 @@ mmap_record::map_pages (caddr_t addr, SIZE_T len) } if (!noreserve () && !VirtualProtect (get_address () + off * wincap.page_size (), - len * wincap.page_size (), gen_protect (), + len * wincap.page_size (), + ::gen_protect (new_prot, get_flags ()), &old_prot)) { __seterrno (); @@ -614,7 +619,7 @@ mmap_list::del_record (mmap_record *rec) } caddr_t -mmap_list::try_map (void *addr, size_t len, int flags, off_t off) +mmap_list::try_map (void *addr, size_t len, int new_prot, int flags, off_t off) { mmap_record *rec; @@ -628,7 +633,7 @@ mmap_list::try_map (void *addr, size_t len, int flags, off_t off) break; if (rec && rec->compatible_flags (flags)) { - if ((off = rec->map_pages (len)) == (off_t) -1) + if ((off = rec->map_pages (len, new_prot)) == (off_t) -1) return (caddr_t) MAP_FAILED; return (caddr_t) rec->get_address () + off; } @@ -655,7 +660,7 @@ mmap_list::try_map (void *addr, size_t len, int flags, off_t off) set_errno (EINVAL); return (caddr_t) MAP_FAILED; } - if (!rec->map_pages ((caddr_t) addr, len)) + if (!rec->map_pages ((caddr_t) addr, len, new_prot)) return (caddr_t) MAP_FAILED; return (caddr_t) addr; } @@ -1051,7 +1056,7 @@ mmap (void *addr, size_t len, int prot, int flags, int fd, off_t off) /* Test if an existing anonymous mapping can be recycled. */ if (map_list && anonymous (flags)) { - caddr_t tried = map_list->try_map (addr, len, flags, off); + caddr_t tried = map_list->try_map (addr, len, prot, flags, off); /* try_map returns NULL if no map matched, otherwise it returns a valid address, or MAP_FAILED in case of a fatal error. */ if (tried) diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index e99739241c..eb97c3d4aa 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -61,3 +61,6 @@ Fixes: - Fix several problems triggered when a lot of SIGSTOP/SIGCONT signals are received rapidly. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html + +- Fix the protection when mmap(2) recycles unused pages. + Addresses: https://cygwin.com/pipermail/cygwin/2024-December/256911.html From 5bb9e8875debd48bfb980f0331fa1eb6e153d8d0 Mon Sep 17 00:00:00 2001 From: Ken Brown Date: Wed, 18 Dec 2024 11:43:09 -0500 Subject: [PATCH 055/116] Cygwin: mmap_list::try_map: fix a condition in a test of an mmap request In testing whether the requested area is contained in an existing mapped region, an incorrect condition was used due to a misinterpretation of the u_addr and u_len variables. Addresses: https://cygwin.com/pipermail/cygwin/2024-December/256913.html Fixes: c68de3a262fe5 ("* mmap.cc (class mmap_record): Declare new map_pages method with address parameter.") Signed-off-by: Ken Brown (cherry picked from commit 67bef16f7edf8642366ff55399bf9cf007c66d52) --- winsup/cygwin/mm/mmap.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/mm/mmap.cc b/winsup/cygwin/mm/mmap.cc index 4fec64b87d..13418d782b 100644 --- a/winsup/cygwin/mm/mmap.cc +++ b/winsup/cygwin/mm/mmap.cc @@ -651,7 +651,7 @@ mmap_list::try_map (void *addr, size_t len, int new_prot, int flags, off_t off) break; if (rec) { - if (u_addr > (caddr_t) addr || u_addr + len < (caddr_t) addr + len + if (u_addr > (caddr_t) addr || u_addr + u_len < (caddr_t) addr + len || !rec->compatible_flags (flags)) { /* Partial match only, or access mode doesn't match. */ From bdad035f0baf6fa584ca10913e9948c0aba2970e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 20:40:45 +0300 Subject: [PATCH 056/116] Add MSYS2 triplet --- compile | 4 ++-- config.guess | 3 +++ config.rpath | 8 +++---- config/dfp.m4 | 3 ++- config/elf.m4 | 2 +- config/lthostflags.m4 | 2 +- config/mmap.m4 | 4 ++-- config/picflag.m4 | 2 ++ config/tcl.m4 | 4 ++-- configure | 22 +++++++++--------- configure.ac | 20 ++++++++--------- libtool.m4 | 36 +++++++++++++++++------------- ltmain.sh | 52 +++++++++++++++++++++---------------------- ltoptions.m4 | 2 +- newlib/configure | 2 +- newlib/configure.host | 8 +++---- 16 files changed, 93 insertions(+), 81 deletions(-) diff --git a/compile b/compile index a85b723c7e..a4ecdb2519 100755 --- a/compile +++ b/compile @@ -53,7 +53,7 @@ func_file_conv () MINGW*) file_conv=mingw ;; - CYGWIN*) + CYGWIN*|MSYS*) file_conv=cygwin ;; *) @@ -67,7 +67,7 @@ func_file_conv () mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; - cygwin/*) + cygwin/*|msys/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) diff --git a/config.guess b/config.guess index 1972fda8eb..a922fa3881 100755 --- a/config.guess +++ b/config.guess @@ -914,6 +914,9 @@ EOF amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-pc-cygwin exit ;; + amd64:MSYS*:*:* | x86_64:MSYS*:*:*) + echo x86_64-unknown-msys + exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" exit ;; diff --git a/config.rpath b/config.rpath index 4dea75957c..4f12c27e02 100755 --- a/config.rpath +++ b/config.rpath @@ -109,7 +109,7 @@ hardcode_direct=no hardcode_minus_L=no case "$host_os" in - cygwin* | mingw* | pw32*) + cygwin* | msys* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. @@ -149,7 +149,7 @@ if test "$with_gnu_ld" = yes; then ld_shlibs=no fi ;; - cygwin* | mingw* | pw32*) + cygwin* | msys* | mingw* | pw32*) # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' @@ -268,7 +268,7 @@ else ;; bsdi4*) ;; - cygwin* | mingw* | pw32*) + cygwin* | msys* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is @@ -437,7 +437,7 @@ case "$host_os" in ;; bsdi4*) ;; - cygwin* | mingw* | pw32*) + cygwin* | msys* | mingw* | pw32*) shrext=.dll ;; darwin* | rhapsody*) diff --git a/config/dfp.m4 b/config/dfp.m4 index 5b29089cec..b03bcf0ccb 100644 --- a/config/dfp.m4 +++ b/config/dfp.m4 @@ -23,7 +23,8 @@ Valid choices are 'yes', 'bid', 'dpd', and 'no'.]) ;; powerpc*-*-linux* | i?86*-*-linux* | x86_64*-*-linux* | s390*-*-linux* | \ i?86*-*-elfiamcu | i?86*-*-gnu* | \ i?86*-*-mingw* | x86_64*-*-mingw* | \ - i?86*-*-cygwin* | x86_64*-*-cygwin*) + i?86*-*-cygwin* | x86_64*-*-cygwin* | \ + i?86*-*-msys* | x86_64*-*-msys*) enable_decimal_float=yes ;; *) diff --git a/config/elf.m4 b/config/elf.m4 index 5f5cd88da0..b8491de764 100644 --- a/config/elf.m4 +++ b/config/elf.m4 @@ -15,7 +15,7 @@ AC_REQUIRE([AC_CANONICAL_TARGET]) target_elf=no case $target in - *-darwin* | *-aix* | *-cygwin* | *-mingw* | *-aout* | *-*coff* | \ + *-darwin* | *-aix* | *-cygwin* | *-msys* | *-mingw* | *-aout* | *-*coff* | \ *-msdosdjgpp* | *-vms* | *-wince* | *-*-pe* | \ alpha*-dec-osf* | hppa[[12]]*-*-hpux* | \ nvptx-*-none) diff --git a/config/lthostflags.m4 b/config/lthostflags.m4 index bc0f59ee79..ad977d43dc 100644 --- a/config/lthostflags.m4 +++ b/config/lthostflags.m4 @@ -13,7 +13,7 @@ AC_DEFUN([ACX_LT_HOST_FLAGS], [ AC_REQUIRE([AC_CANONICAL_SYSTEM]) case $host in - *-cygwin* | *-mingw*) + *-cygwin* | *-msys* | *-mingw*) # 'host' will be top-level target in the case of a target lib, # we must compare to with_cross_host to decide if this is a native # or cross-compiler and select where to install dlls appropriately. diff --git a/config/mmap.m4 b/config/mmap.m4 index fba0d9d365..df2c778524 100644 --- a/config/mmap.m4 +++ b/config/mmap.m4 @@ -42,7 +42,7 @@ else # Systems known to be in this category are Windows (all variants), # VMS, and Darwin. case "$host_os" in - *vms* | cygwin* | pe | mingw* | darwin* | ultrix* | hpux10* | hpux11.00) + *vms* | cygwin* | msys* | pe | mingw* | darwin* | ultrix* | hpux10* | hpux11.00) gcc_cv_func_mmap_dev_zero=no ;; *) gcc_cv_func_mmap_dev_zero=yes;; @@ -74,7 +74,7 @@ else # above for use of /dev/zero. # Systems known to be in this category are Windows, VMS, and SCO Unix. case "$host_os" in - *vms* | cygwin* | pe | mingw* | sco* | udk* ) + *vms* | cygwin* | msys* | pe | mingw* | sco* | udk* ) gcc_cv_func_mmap_anon=no ;; *) gcc_cv_func_mmap_anon=yes;; diff --git a/config/picflag.m4 b/config/picflag.m4 index 614421d2a9..9d507ba3f8 100644 --- a/config/picflag.m4 +++ b/config/picflag.m4 @@ -25,6 +25,8 @@ case "${$2}" in ;; i[[34567]]86-*-cygwin* | x86_64-*-cygwin*) ;; + i[[34567]]86-*-msys* | x86_64-*-msys*) + ;; i[[34567]]86-*-mingw* | x86_64-*-mingw*) ;; i[[34567]]86-*-nto-qnx*) diff --git a/config/tcl.m4 b/config/tcl.m4 index 4542a4b23d..209bd8d9b8 100644 --- a/config/tcl.m4 +++ b/config/tcl.m4 @@ -33,7 +33,7 @@ AC_DEFUN([SC_PATH_TCLCONFIG], [ # First check to see if --with-tcl was specified. case "${host}" in - *-*-cygwin*) platDir="win" ;; + *-*-cygwin* | *-*-msys*) platDir="win" ;; *) platDir="unix" ;; esac if test x"${with_tclconfig}" != x ; then @@ -165,7 +165,7 @@ AC_DEFUN([SC_PATH_TKCONFIG], [ # then check for a private Tk library case "${host}" in - *-*-cygwin*) platDir="win" ;; + *-*-cygwin* | *-*-msys*) platDir="win" ;; *) platDir="unix" ;; esac if test x"${ac_cv_c_tkconfig}" = x ; then diff --git a/configure b/configure index 9477153056..1474838bd6 100755 --- a/configure +++ b/configure @@ -3088,7 +3088,7 @@ fi # Configure extra directories which are host specific case "${host}" in - *-cygwin*) + *-cygwin* | *-msys*) configdirs="$configdirs libtermcap" ;; esac @@ -3609,7 +3609,7 @@ esac # Disable the go frontend on systems where it is known to not work. Please keep # this in sync with contrib/config-list.mk. case "${target}" in -*-*-darwin* | *-*-cygwin* | *-*-mingw* | *-*-aix*) +*-*-darwin* | *-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-aix*) unsupported_languages="$unsupported_languages go" ;; esac @@ -3622,7 +3622,7 @@ if test x$enable_libgo = x; then # PR 46986 noconfigdirs="$noconfigdirs target-libgo" ;; - *-*-cygwin* | *-*-mingw*) + *-*-cygwin* | *-*-msys* | *-*-mingw*) noconfigdirs="$noconfigdirs target-libgo" ;; *-*-aix*) @@ -3894,7 +3894,7 @@ case "${target}" in i[3456789]86-*-mingw*) target_configdirs="$target_configdirs target-winsup" ;; - *-*-cygwin*) + *-*-cygwin* | *-*-msys*) target_configdirs="$target_configdirs target-libtermcap target-winsup" noconfigdirs="$noconfigdirs target-libgloss" # always build newlib if winsup directory is present. @@ -4038,7 +4038,7 @@ case "${host}" in i[3456789]86-*-msdosdjgpp*) host_makefile_frag="config/mh-djgpp" ;; - *-cygwin*) + *-cygwin* | *-msys*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking to see if cat works as expected" >&5 $as_echo_n "checking to see if cat works as expected... " >&6; } @@ -6206,7 +6206,7 @@ fi target_elf=no case $target in - *-darwin* | *-aix* | *-cygwin* | *-mingw* | *-aout* | *-*coff* | \ + *-darwin* | *-aix* | *-cygwin* | *-msys* | *-mingw* | *-aout* | *-*coff* | \ *-msdosdjgpp* | *-vms* | *-wince* | *-*-pe* | \ alpha*-dec-osf* | hppa[12]*-*-hpux* | \ nvptx-*-none) @@ -6224,7 +6224,7 @@ if test $target_elf = yes; then : else if test x"$default_enable_lto" = x"yes" ; then case $target in - *-apple-darwin9* | *-cygwin* | *-mingw* | *djgpp*) ;; + *-apple-darwin9* | *-cygwin* | *-msys* | *-mingw* | *djgpp*) ;; # On other non-ELF platforms, LTO has yet to be validated. *) enable_lto=no ;; esac @@ -6235,7 +6235,7 @@ else # warn during gcc/ subconfigure; unless you're bootstrapping with # -flto it won't be needed until after installation anyway. case $target in - *-cygwin* | *-mingw* | *-apple-darwin* | *djgpp*) ;; + *-cygwin* | *-msys* | *-mingw* | *-apple-darwin* | *djgpp*) ;; *) if test x"$enable_lto" = x"yes"; then as_fn_error $? "LTO support is not enabled for this target." "$LINENO" 5 fi @@ -6245,7 +6245,7 @@ else # Among non-ELF, only Windows platforms support the lto-plugin so far. # Build it unless LTO was explicitly disabled. case $target in - *-cygwin* | *-mingw*) build_lto_plugin=$enable_lto ;; + *-cygwin* | *-msys* | *-mingw*) build_lto_plugin=$enable_lto ;; *) ;; esac @@ -7130,7 +7130,7 @@ rm -f conftest* case "${host}" in *-*-hpux*) RPATH_ENVVAR=SHLIB_PATH ;; *-*-darwin*) RPATH_ENVVAR=DYLD_LIBRARY_PATH ;; - *-*-mingw* | *-*-cygwin ) RPATH_ENVVAR=PATH ;; + *-*-mingw* | *-*-cygwin | *-msys ) RPATH_ENVVAR=PATH ;; *) RPATH_ENVVAR=LD_LIBRARY_PATH ;; esac @@ -7648,7 +7648,7 @@ case " $target_configdirs " in case " $target_configargs " in *" --with-newlib "*) case "$target" in - *-cygwin*) + *-cygwin* | *-msys*) FLAGS_FOR_TARGET=$FLAGS_FOR_TARGET' -L$$r/$(TARGET_SUBDIR)/winsup/cygwin -isystem $$s/winsup/cygwin/include' ;; esac diff --git a/configure.ac b/configure.ac index 05ddf69870..3ed8a1b888 100644 --- a/configure.ac +++ b/configure.ac @@ -409,7 +409,7 @@ AC_ARG_ENABLE(compressed_debug_sections, # Configure extra directories which are host specific case "${host}" in - *-cygwin*) + *-cygwin* | *-msys*) configdirs="$configdirs libtermcap" ;; esac @@ -893,7 +893,7 @@ esac # Disable the go frontend on systems where it is known to not work. Please keep # this in sync with contrib/config-list.mk. case "${target}" in -*-*-darwin* | *-*-cygwin* | *-*-mingw* | *-*-aix*) +*-*-darwin* | *-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-aix*) unsupported_languages="$unsupported_languages go" ;; esac @@ -906,7 +906,7 @@ if test x$enable_libgo = x; then # PR 46986 noconfigdirs="$noconfigdirs target-libgo" ;; - *-*-cygwin* | *-*-mingw*) + *-*-cygwin* | *-*-msys* | *-*-mingw*) noconfigdirs="$noconfigdirs target-libgo" ;; *-*-aix*) @@ -1178,7 +1178,7 @@ case "${target}" in i[[3456789]]86-*-mingw*) target_configdirs="$target_configdirs target-winsup" ;; - *-*-cygwin*) + *-*-cygwin* | *-*-msys*) target_configdirs="$target_configdirs target-libtermcap target-winsup" noconfigdirs="$noconfigdirs target-libgloss" # always build newlib if winsup directory is present. @@ -1322,7 +1322,7 @@ case "${host}" in i[[3456789]]86-*-msdosdjgpp*) host_makefile_frag="config/mh-djgpp" ;; - *-cygwin*) + *-cygwin* | *-msys*) ACX_CHECK_CYGWIN_CAT_WORKS host_makefile_frag="config/mh-cygwin" ;; @@ -1809,7 +1809,7 @@ ACX_ELF_TARGET_IFELSE([# ELF platforms build the lto-plugin always. build_lto_plugin=yes ],[if test x"$default_enable_lto" = x"yes" ; then case $target in - *-apple-darwin9* | *-cygwin* | *-mingw* | *djgpp*) ;; + *-apple-darwin9* | *-cygwin* | *-msys* | *-mingw* | *djgpp*) ;; # On other non-ELF platforms, LTO has yet to be validated. *) enable_lto=no ;; esac @@ -1820,7 +1820,7 @@ ACX_ELF_TARGET_IFELSE([# ELF platforms build the lto-plugin always. # warn during gcc/ subconfigure; unless you're bootstrapping with # -flto it won't be needed until after installation anyway. case $target in - *-cygwin* | *-mingw* | *-apple-darwin* | *djgpp*) ;; + *-cygwin* | *-msys*| *-mingw* | *-apple-darwin* | *djgpp*) ;; *) if test x"$enable_lto" = x"yes"; then AC_MSG_ERROR([LTO support is not enabled for this target.]) fi @@ -1830,7 +1830,7 @@ ACX_ELF_TARGET_IFELSE([# ELF platforms build the lto-plugin always. # Among non-ELF, only Windows platforms support the lto-plugin so far. # Build it unless LTO was explicitly disabled. case $target in - *-cygwin* | *-mingw*) build_lto_plugin=$enable_lto ;; + *-cygwin* | *-msys* | *-mingw*) build_lto_plugin=$enable_lto ;; *) ;; esac ]) @@ -2652,7 +2652,7 @@ rm -f conftest* case "${host}" in *-*-hpux*) RPATH_ENVVAR=SHLIB_PATH ;; *-*-darwin*) RPATH_ENVVAR=DYLD_LIBRARY_PATH ;; - *-*-mingw* | *-*-cygwin ) RPATH_ENVVAR=PATH ;; + *-*-mingw* | *-*-cygwin | *-*-msys ) RPATH_ENVVAR=PATH ;; *) RPATH_ENVVAR=LD_LIBRARY_PATH ;; esac @@ -3165,7 +3165,7 @@ case " $target_configdirs " in case " $target_configargs " in *" --with-newlib "*) case "$target" in - *-cygwin*) + *-cygwin* | *-msys*) FLAGS_FOR_TARGET=$FLAGS_FOR_TARGET' -L$$r/$(TARGET_SUBDIR)/winsup/cygwin -isystem $$s/winsup/cygwin/include' ;; esac diff --git a/libtool.m4 b/libtool.m4 index a216bb14e9..0d6d17a668 100644 --- a/libtool.m4 +++ b/libtool.m4 @@ -1521,7 +1521,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl lt_cv_sys_max_cmd_len=-1; ;; - cygwin* | mingw* | cegcc*) + cygwin* | msys* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, @@ -1763,7 +1763,7 @@ else lt_cv_dlopen_libs= ;; - cygwin*) + cygwin* | msys*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; @@ -2234,14 +2234,14 @@ bsdi[[45]]*) # libtool to hard-code these into programs ;; -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | msys* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in - yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + yes,cygwin* | yes,msys* | yes,mingw* | yes,pw32* | yes,cegcc*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ @@ -2262,6 +2262,12 @@ cygwin* | mingw* | pw32* | cegcc*) cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) + ;; + msys*) + # Msys DLLs use 'msys-' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/msys-/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; @@ -3021,7 +3027,7 @@ bsdi[[45]]*) lt_cv_file_magic_test_file=/shlib/libc.so ;; -cygwin*) +cygwin* | msys*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' @@ -3307,7 +3313,7 @@ AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in -*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-msys* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) @@ -3382,7 +3388,7 @@ case $host_os in aix*) symcode='[[BCDT]]' ;; -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | msys* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) @@ -3629,7 +3635,7 @@ m4_if([$1], [CXX], [ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; - mingw* | cygwin* | os2* | pw32* | cegcc*) + mingw* | cygwin* | msys* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style @@ -3942,7 +3948,7 @@ m4_if([$1], [CXX], [ # PIC is the default for these OSes. ;; - mingw* | cygwin* | pw32* | os2* | cegcc*) + mingw* | cygwin* | msys* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style @@ -4025,7 +4031,7 @@ m4_if([$1], [CXX], [ fi ;; - mingw* | cygwin* | pw32* | os2* | cegcc*) + mingw* | cygwin* | msys* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], @@ -4258,7 +4264,7 @@ m4_if([$1], [CXX], [ pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; - cygwin* | mingw* | cegcc*) + cygwin* | msys* | mingw* | cegcc*) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' ;; *) @@ -4310,7 +4316,7 @@ dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. @@ -4425,7 +4431,7 @@ _LT_EOF fi ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' @@ -4798,7 +4804,7 @@ _LT_EOF _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is @@ -5742,7 +5748,7 @@ if test "$_lt_caught_CXX_error" != yes; then esac ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' diff --git a/ltmain.sh b/ltmain.sh index 9503ec85d7..307a33979e 100644 --- a/ltmain.sh +++ b/ltmain.sh @@ -976,7 +976,7 @@ func_enable_tag () case $host in - *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* ) + *cygwin* | *msys* | *mingw* | *pw32* | *cegcc* | *solaris2* ) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; @@ -1453,7 +1453,7 @@ func_mode_compile () # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in - cygwin* | mingw* | pw32* | os2* | cegcc*) + cygwin* | msys* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac @@ -2279,7 +2279,7 @@ func_mode_install () 'exit $?' tstripme="$stripme" case $host_os in - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" @@ -2385,7 +2385,7 @@ func_mode_install () # Do a test to see if this is really a libtool program. case $host in - *cygwin* | *mingw*) + *cygwin* | *msys* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result @@ -2460,7 +2460,7 @@ func_mode_install () # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in - */usr/bin/install*,*cygwin*) + */usr/bin/install*,*cygwin*|*/usr/bin/install*,*msys*) case $file:$destfile in *.exe:*.exe) # this is ok @@ -2595,7 +2595,7 @@ extern \"C\" { $RM $export_symbols ${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' < "$nlist" > "$export_symbols" case $host in - *cygwin* | *mingw* | *cegcc* ) + *cygwin* | *msys* | *mingw* | *cegcc* ) echo EXPORTS > "$output_objdir/$outputname.def" cat "$export_symbols" >> "$output_objdir/$outputname.def" ;; @@ -2607,7 +2607,7 @@ extern \"C\" { $GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" case $host in - *cygwin* | *mingw* | *cegcc* ) + *cygwin* | *msys* | *mingw* | *cegcc* ) echo EXPORTS > "$output_objdir/$outputname.def" cat "$nlist" >> "$output_objdir/$outputname.def" ;; @@ -2663,7 +2663,7 @@ typedef struct { } lt_dlsymlist; " case $host in - *cygwin* | *mingw* | *cegcc* ) + *cygwin* | *msys* | *mingw* | *cegcc* ) echo >> "$output_objdir/$my_dlsyms" "\ /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation @@ -2749,7 +2749,7 @@ static const void *lt_preloaded_setup() { # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in - *cygwin* | *mingw* | *cegcc* ) + *cygwin* | *msys* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` @@ -3192,7 +3192,7 @@ func_to_host_path () func_to_host_path_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` ;; - *cygwin* ) + *cygwin* | *msys* ) func_to_host_path_result=`cygpath -w "$1" | $SED -e "$lt_sed_naive_backslashify"` ;; @@ -3265,7 +3265,7 @@ func_to_host_pathlist () ( cmd //c echo "$func_to_host_pathlist_tmp1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` ;; - *cygwin* ) + *cygwin* | *msys* ) func_to_host_pathlist_result=`cygpath -w -p "$func_to_host_pathlist_tmp1" | $SED -e "$lt_sed_naive_backslashify"` ;; @@ -3571,7 +3571,7 @@ main (int argc, char *argv[]) { EOF case "$host" in - *mingw* | *cygwin* ) + *mingw* | *cygwin* | *msys* ) # make stdout use "unix" line endings echo " setmode(1,_O_BINARY);" ;; @@ -4233,7 +4233,7 @@ func_mode_link () { $opt_debug case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + *-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra @@ -4713,7 +4713,7 @@ func_mode_link () ;; esac case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + *-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; @@ -4733,7 +4733,7 @@ func_mode_link () -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + *-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; @@ -4813,7 +4813,7 @@ func_mode_link () -no-install) case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + *-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" @@ -5772,7 +5772,7 @@ func_mode_link () if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in - *cygwin* | *mingw* | *cegcc*) + *cygwin* | *msys* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded notinst_deplibs="$notinst_deplibs $lib" need_relink=no @@ -5842,7 +5842,7 @@ func_mode_link () elif test -n "$soname_spec"; then # bleh windows case $host in - *cygwin* | mingw* | *cegcc*) + *cygwin* | msys* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" @@ -6693,7 +6693,7 @@ func_mode_link () if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + *-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) @@ -7194,7 +7194,7 @@ EOF orig_export_symbols= case $host_os in - cygwin* | mingw* | cegcc*) + cygwin* | msys* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then @@ -7710,7 +7710,7 @@ EOF prog) case $host in - *cygwin*) func_stripname '' '.exe' "$output" + *cygwin* | *msys*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ @@ -7823,7 +7823,7 @@ EOF esac fi case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + *-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; @@ -7901,7 +7901,7 @@ EOF # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=no ;; - *cygwin* | *mingw* ) + *cygwin* | *msys* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi @@ -8029,14 +8029,14 @@ EOF esac # test for cygwin because mv fails w/o .exe extensions case $host in - *cygwin*) + *cygwin* | *msys*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in - *cygwin* | *mingw* ) + *cygwin* | *msys* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result @@ -8343,7 +8343,7 @@ EOF # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in - *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + *cygwin*,*lai,yes,no,*.dll | *msys*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test "x$bindir" != x ; then diff --git a/ltoptions.m4 b/ltoptions.m4 index 5ef12ced2a..5e7bc34702 100644 --- a/ltoptions.m4 +++ b/ltoptions.m4 @@ -126,7 +126,7 @@ LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in -*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) +*-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) diff --git a/newlib/configure b/newlib/configure index 6a542bb884..00de6b93a2 100755 --- a/newlib/configure +++ b/newlib/configure @@ -4283,7 +4283,7 @@ else fi -ac_ext=c +:cn ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' diff --git a/newlib/configure.host b/newlib/configure.host index 3861834663..2023e58f57 100644 --- a/newlib/configure.host +++ b/newlib/configure.host @@ -195,7 +195,7 @@ case "${host_cpu}" in shared_machine_dir=shared_x86 # Don't use for these since they provide their own setjmp. case ${host} in - *-*-sco* | *-*-cygwin*) + *-*-sco* | *-*-cygwin* | *-*-msys*) ;; *) mach_add_setjmp=true @@ -407,7 +407,7 @@ fi if [ "x${newlib_mb}" = "x" ]; then case "${host}" in - *-*-cygwin*) + *-*-cygwin*|*-*-msys*) newlib_mb=yes ;; esac @@ -426,7 +426,7 @@ fi # THIS TABLE IS ALPHA SORTED. KEEP IT THAT WAY. case "${host}" in - *-*-cygwin*) + *-*-cygwin* | *-*-msys*) posix_dir=posix xdr_dir=xdr ;; @@ -589,7 +589,7 @@ esac # THIS TABLE IS ALPHA SORTED. KEEP IT THAT WAY. case "${host}" in - *-*-cygwin*) + *-*-cygwin* | *-*-msys*) test -z "$cygwin_srcdir" && cygwin_srcdir="${abs_newlib_basedir}/../winsup/cygwin" export cygwin_srcdir default_newlib_io_c99_formats="yes" From 900232bfff4076c483307b4af8f2bbf9b50a600f Mon Sep 17 00:00:00 2001 From: Kaleb Barrett Date: Sun, 14 Mar 2021 18:58:55 -0500 Subject: [PATCH 057/116] Fix msys library name in import libraries 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. --- winsup/cygwin/scripts/speclib | 1 + 1 file changed, 1 insertion(+) diff --git a/winsup/cygwin/scripts/speclib b/winsup/cygwin/scripts/speclib index 41a3a8e139..42a02c511b 100755 --- a/winsup/cygwin/scripts/speclib +++ b/winsup/cygwin/scripts/speclib @@ -38,6 +38,7 @@ while (<$nm_fd>) { study; if (/ I _?(.*)_dll_iname/o) { $dllname = $1; + $dllname =~ s/_2_0/-2.0/; } else { my ($file, $member, $symbol) = m%^([^:]*):([^:]*(?=:))?.* T (.*)%o; next if !defined($symbol) || $symbol =~ $exclude_regex; From 585fadf7eab7cc83f6445adcd30b5c2b2e9357f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 21:09:17 +0300 Subject: [PATCH 058/116] Rename dll from cygwin to msys --- winsup/cygserver/transport_pipes.h | 4 +++ winsup/cygwin/Makefile.am | 27 ++++++++++--------- winsup/cygwin/crt0.c | 8 ++++++ winsup/cygwin/cygwin.din | 6 ++--- winsup/cygwin/cygwin.sc.in | 4 +++ winsup/cygwin/dcrt0.cc | 4 +++ winsup/cygwin/dlfcn.cc | 5 ++++ winsup/cygwin/dll_init.cc | 4 +++ winsup/cygwin/dtable.cc | 6 +++++ winsup/cygwin/exceptions.cc | 4 +-- winsup/cygwin/fhandler/pipe.cc | 4 +++ winsup/cygwin/fhandler/pty.cc | 20 ++++++++++++++ winsup/cygwin/hookapi.cc | 4 +++ winsup/cygwin/include/cygwin/cygwin_dll.h | 10 +++---- winsup/cygwin/include/cygwin/version.h | 8 ++++++ winsup/cygwin/lib/_cygwin_crt0_common.cc | 4 +++ winsup/cygwin/lib/crt0.h | 4 +++ winsup/cygwin/lib/cygwin_attach_dll.c | 8 ++++++ winsup/cygwin/lib/cygwin_crt0.c | 8 ++++++ .../cygwin/local_includes/cygserver_setpwd.h | 4 +++ winsup/cygwin/scripts/mkvers.sh | 6 ++--- winsup/cygwin/sec/auth.cc | 8 +++--- winsup/cygwin/syscalls.cc | 4 +-- winsup/cygwin/syslog.cc | 4 +++ winsup/cygwin/winver.rc | 2 +- winsup/testsuite/winsup.api/cygload.cc | 10 +++---- winsup/testsuite/winsup.api/cygload.h | 2 +- winsup/utils/ldd.cc | 2 +- winsup/utils/loadlib.h | 6 ++--- winsup/utils/mingw/cygcheck.cc | 27 +++++++++---------- winsup/utils/mingw/strace.cc | 9 +++---- winsup/utils/path.cc | 12 ++++----- winsup/utils/ssp.c | 8 +++--- 33 files changed, 174 insertions(+), 72 deletions(-) diff --git a/winsup/cygserver/transport_pipes.h b/winsup/cygserver/transport_pipes.h index e101623d24..66272bc86c 100644 --- a/winsup/cygserver/transport_pipes.h +++ b/winsup/cygserver/transport_pipes.h @@ -11,7 +11,11 @@ details. */ #ifndef _TRANSPORT_PIPES_H #define _TRANSPORT_PIPES_H +#ifdef __MSYS__ +#define PIPE_NAME_PREFIX L"\\\\.\\pipe\\msys-" +#else #define PIPE_NAME_PREFIX L"\\\\.\\pipe\\cygwin-" +#endif #define PIPE_NAME_SUFFIX L"-lpc" /* Named pipes based transport, for security on NT */ diff --git a/winsup/cygwin/Makefile.am b/winsup/cygwin/Makefile.am index 376c79fc3c..e65e675bcd 100644 --- a/winsup/cygwin/Makefile.am +++ b/winsup/cygwin/Makefile.am @@ -37,12 +37,12 @@ newlib_build=$(target_builddir)/newlib toollibdir=$(tooldir)/lib toolincludedir=$(tooldir)/include -# Parameters used in building the cygwin.dll. +# Parameters used in building the msys-2.0.dll. -DLL_NAME=cygwin1.dll -NEW_DLL_NAME=new-cygwin1.dll -DEF_FILE=cygwin.def -LIB_NAME=libcygwin.a +DLL_NAME=msys-2.0.dll +NEW_DLL_NAME=new-msys-2.0.dll +DEF_FILE=msys.def +LIB_NAME=libmsys-2.0.a # # sources @@ -584,16 +584,16 @@ LIBSERVER = $(cygserver_blddir)/libcygserver.a $(LIBSERVER): $(MAKE) -C $(cygserver_blddir) libcygserver.a -# We build as new-cygwin1.dll and rename at install time to overcome native +# We build as new-msys-2.0.dll and rename at install time to overcome native # rebuilding issues (we don't want the build tools to see a partially built -# cygwin1.dll and attempt to use it instead of the old one). +# msys-2.0.dll and attempt to use it instead of the old one). # linker script LDSCRIPT=cygwin.sc $(LDSCRIPT): $(LDSCRIPT).in $(AM_V_GEN)$(CC) -E - -P < $^ -o $@ -# cygwin dll +# msys-2.0 dll # Set PE and export table header timestamps to zero for reproducible builds. $(NEW_DLL_NAME): $(LDSCRIPT) libdll.a $(VERSION_OFILES) $(LIBSERVER)\ $(newlib_build)/libm.a $(newlib_build)/libc.a @@ -602,18 +602,18 @@ $(NEW_DLL_NAME): $(LDSCRIPT) libdll.a $(VERSION_OFILES) $(LIBSERVER)\ -Wl,--gc-sections -nostdlib -Wl,-T$(LDSCRIPT) \ -Wl,--dynamicbase -static \ $${SOURCE_DATE_EPOCH:+-Wl,--no-insert-timestamp} \ - -Wl,--heap=0 -Wl,--out-implib,cygdll.a -shared -o $@ \ + -Wl,--heap=0 -Wl,--out-implib,msysdll.a -shared -o $@ \ -e @DLL_ENTRY@ $(DEF_FILE) \ -Wl,-whole-archive libdll.a -Wl,-no-whole-archive \ $(VERSION_OFILES) \ $(LIBSERVER) \ $(newlib_build)/libm.a \ $(newlib_build)/libc.a \ - -lgcc -lkernel32 -lntdll -Wl,-Map,cygwin.map + -lgcc -lkernel32 -lntdll -Wl,-Map,msys.map @$(MKDIR_P) ${target_builddir}/winsup/testsuite/testinst/bin/ $(AM_V_at)$(INSTALL_PROGRAM) $(NEW_DLL_NAME) ${target_builddir}/winsup/testsuite/testinst/bin/$(DLL_NAME) -# cygwin import library +# msys-2.0 import library toolopts=--cpu=@target_cpu@ --ar=@AR@ --as=@AS@ --nm=@NM@ --objcopy=@OBJCOPY@ $(DEF_FILE): scripts/gendef cygwin.din @@ -626,13 +626,14 @@ sigfe.s: $(DEF_FILE) tlsoffsets LIBCOS=$(addsuffix .o,$(basename $(LIB_FILES))) $(LIB_NAME): $(DEF_FILE) $(LIBCOS) | $(NEW_DLL_NAME) - $(AM_V_GEN)$(srcdir)/scripts/mkimport $(toolopts) $(NEW_FUNCTIONS) $@ cygdll.a $(wordlist 2,99,$^) + $(AM_V_GEN)$(srcdir)/scripts/mkimport $(toolopts) $(NEW_FUNCTIONS) $@ msysdll.a $(wordlist 2,99,$^) # sublibs # import libraries for some subset of symbols indicated by given objects speclib=\ $(srcdir)/scripts/speclib $(toolopts) \ --exclude='cygwin' \ + --exclude='msys' \ --exclude='(?i:dll)' \ --exclude='reloc' \ --exclude='^main$$' \ @@ -679,7 +680,7 @@ all-local: $(LIB_NAME) $(SUBLIBS) clean-local: -rm -f $(BUILT_SOURCES) -rm -f $(DEF_FILE) sigfe.s - -rm -f cygwin.sc cygdll.a cygwin.map + -rm -f cygwin.sc msysdll.a msys.map -rm -f $(NEW_DLL_NAME) -rm -f $(LIB_NAME) $(SUBLIBS) -rm -f version.cc diff --git a/winsup/cygwin/crt0.c b/winsup/cygwin/crt0.c index 1096e58970..3160df4491 100644 --- a/winsup/cygwin/crt0.c +++ b/winsup/cygwin/crt0.c @@ -9,12 +9,20 @@ details. */ extern int main (int argc, char **argv); +#ifdef __MSYS__ +void msys_crt0 (int (*main) (int, char **)); +#else void cygwin_crt0 (int (*main) (int, char **)); +#endif void mainCRTStartup () { +#ifdef __MSYS__ + msys_crt0 (main); +#else cygwin_crt0 (main); +#endif /* These are never actually called. They are just here to force the inclusion of things like -lbinmode. */ diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index 9e354acc61..76e88df2fc 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -1,4 +1,4 @@ -LIBRARY "cygwin1.dll" BASE=0x180040000 +LIBRARY "msys-2.0.dll" BASE=0x180040000 EXPORTS # Exported variables @@ -404,8 +404,8 @@ cygwin_attach_handle_to_fd SIGFE cygwin_conv_path SIGFE cygwin_conv_path_list SIGFE cygwin_create_path SIGFE -cygwin_detach_dll SIGFE_MAYBE -cygwin_dll_init NOSIGFE +msys_detach_dll SIGFE_MAYBE +msys_dll_init NOSIGFE cygwin_internal NOSIGFE cygwin_logon_user SIGFE cygwin_posix_path_list_p NOSIGFE diff --git a/winsup/cygwin/cygwin.sc.in b/winsup/cygwin/cygwin.sc.in index 69526f5d8a..4dc5daed8d 100644 --- a/winsup/cygwin/cygwin.sc.in +++ b/winsup/cygwin/cygwin.sc.in @@ -1,6 +1,10 @@ #ifdef __x86_64__ OUTPUT_FORMAT(pei-x86-64) +# ifdef __MSYS__ +SEARCH_DIR("/usr/x86_64-pc-msys/lib/w32api"); SEARCH_DIR("=/usr/lib/w32api"); +# else SEARCH_DIR("/usr/x86_64-pc-cygwin/lib/w32api"); SEARCH_DIR("=/usr/lib/w32api"); +# endif #else #error unimplemented for this target #endif diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index ff7e6ec50f..16b624eab5 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -1077,7 +1077,11 @@ dll_crt0 (per_process *uptr) See winsup/testsuite/cygload for an example of how to use cygwin1.dll from MSVC and non-cygwin MinGW applications. */ extern "C" void +#ifdef __MSYS__ +msys_dll_init () +#else cygwin_dll_init () +#endif { static int _fmode; diff --git a/winsup/cygwin/dlfcn.cc b/winsup/cygwin/dlfcn.cc index fb70524735..7367d29713 100644 --- a/winsup/cygwin/dlfcn.cc +++ b/winsup/cygwin/dlfcn.cc @@ -147,8 +147,13 @@ collect_basenames (pathfinder::basenamelist & basenames, /* If the basename starts with "lib", ... */ if (!strncmp (basename, "lib", 3)) { +#ifdef __MSYS__ + /* ... replace "lib" with "msys-", before ... */ + basenames.appendv ("msys-", 5, basename+3, baselen-3, ext, extlen, NULL); +#else /* ... replace "lib" with "cyg", before ... */ basenames.appendv ("cyg", 3, basename+3, baselen-3, ext, extlen, NULL); +#endif } /* ... using original basename with new suffix. */ basenames.appendv (basename, baselen, ext, extlen, NULL); diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc index 1a047511f8..7c5f8cc9fd 100644 --- a/winsup/cygwin/dll_init.cc +++ b/winsup/cygwin/dll_init.cc @@ -874,7 +874,11 @@ dll_dllcrt0_1 (VOID *x) } extern "C" void +#ifdef __MSYS__ +msys_detach_dll (dll *) +#else cygwin_detach_dll (dll *) +#endif { HANDLE retaddr; if (_my_tls.isinitialized ()) diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc index 9508f3e0bb..3c40e0fa3d 100644 --- a/winsup/cygwin/dtable.cc +++ b/winsup/cygwin/dtable.cc @@ -998,9 +998,15 @@ handle_to_fn (HANDLE h, char *posix_fn) if (wcsncasecmp (w32, DEV_NAMED_PIPE, DEV_NAMED_PIPE_LEN) == 0) { w32 += DEV_NAMED_PIPE_LEN; +#ifdef __MSYS__ + if (wcsncmp (w32, L"msys-", WCLEN (L"msys-")) != 0) + return false; + w32 += WCLEN (L"msys-"); +#else if (wcsncmp (w32, L"cygwin-", WCLEN (L"cygwin-")) != 0) return false; w32 += WCLEN (L"cygwin-"); +#endif /* Check for installation key and trailing dash. */ w32len = cygheap->installation_key.Length / sizeof (WCHAR); if (w32len diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index a560a3f344..85909290a3 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -526,14 +526,14 @@ int exec_prepared_command (PWCHAR command) PWCHAR rawenv = GetEnvironmentStringsW () ; for (PWCHAR p = rawenv; *p != L'\0'; p = wcschr (p, L'\0') + 1) { - if (wcsncmp (p, L"CYGWIN=", wcslen (L"CYGWIN=")) == 0) + if (wcsncmp (p, L"MSYS=", wcslen (L"MSYS=")) == 0) { PWCHAR q = wcsstr (p, L"error_start") ; /* replace 'error_start=...' with '_rror_start=...' */ if (q) { *q = L'_' ; - SetEnvironmentVariableW (L"CYGWIN", p + wcslen (L"CYGWIN=")) ; + SetEnvironmentVariableW (L"MSYS", p + wcslen (L"MSYS=")) ; } break; } diff --git a/winsup/cygwin/fhandler/pipe.cc b/winsup/cygwin/fhandler/pipe.cc index 6a1ef03b69..7244fa4cd5 100644 --- a/winsup/cygwin/fhandler/pipe.cc +++ b/winsup/cygwin/fhandler/pipe.cc @@ -751,7 +751,11 @@ fhandler_pipe::close () return ret; } +#ifdef __MSYS__ +#define PIPE_INTRO "\\\\.\\pipe\\msys-" +#else #define PIPE_INTRO "\\\\.\\pipe\\cygwin-" +#endif /* Create a pipe, and return handles to the read and write ends, just like CreatePipe, but ensure that the write end permits diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc index 4f0f718127..eb51c6d392 100644 --- a/winsup/cygwin/fhandler/pty.cc +++ b/winsup/cygwin/fhandler/pty.cc @@ -875,7 +875,11 @@ fhandler_pty_slave::open (int flags, mode_t) pipe_reply repl; DWORD len; +#ifdef __MSYS__ + __small_sprintf (buf, "\\\\.\\pipe\\msys-%S-pty%d-master-ctl", +#else __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl", +#endif &cygheap->installation_key, get_minor ()); termios_printf ("dup handles via master control pipe %s", buf); if (!CallNamedPipe (buf, &req, sizeof req, &repl, sizeof repl, @@ -1137,7 +1141,11 @@ fhandler_pty_slave::reset_switch_to_nat_pipe (void) { char pipe[MAX_PATH]; __small_sprintf (pipe, +#ifdef __MSYS__ + "\\\\.\\pipe\\msys-%S-pty%d-master-ctl", +#else "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl", +#endif &cygheap->installation_key, get_minor ()); pipe_request req = { GetCurrentProcessId () }; pipe_reply repl; @@ -2021,7 +2029,11 @@ fhandler_pty_master::close () pipe_reply repl; DWORD len; +#ifdef __MSYS__ + __small_sprintf (buf, "\\\\.\\pipe\\msys-%S-pty%d-master-ctl", +#else __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl", +#endif &cygheap->installation_key, get_minor ()); acquire_output_mutex (mutex_timeout); if (master_ctl) @@ -2927,7 +2939,11 @@ fhandler_pty_master::setup () /* Create master control pipe which allows the master to duplicate the pty pipe handles to processes which deserve it. */ +#ifdef __MSYS__ + __small_sprintf (buf, "\\\\.\\pipe\\msys-%S-pty%d-master-ctl", +#else __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl", +#endif &cygheap->installation_key, unit); master_ctl = CreateNamedPipe (buf, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, @@ -3816,7 +3832,11 @@ fhandler_pty_slave::transfer_input (tty::xfer_dir dir, HANDLE from, tty *ttyp, { char pipe[MAX_PATH]; __small_sprintf (pipe, +#ifdef __MSYS__ + "\\\\.\\pipe\\msys-%S-pty%d-master-ctl", +#else "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl", +#endif &cygheap->installation_key, ttyp->get_minor ()); pipe_request req = { GetCurrentProcessId () }; pipe_reply repl; diff --git a/winsup/cygwin/hookapi.cc b/winsup/cygwin/hookapi.cc index ee2edbafee..9f31a716c4 100644 --- a/winsup/cygwin/hookapi.cc +++ b/winsup/cygwin/hookapi.cc @@ -379,7 +379,11 @@ hook_or_detect_cygwin (const char *name, const void *fn, WORD& subsys, HANDLE h) for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++) { if (!ascii_strcasematch (rva (PSTR, map ?: (char *) hm, pd->Name - delta), +#ifdef __MSYS__ + "msys-2.0.dll")) +#else "cygwin1.dll")) +#endif continue; if (!fn) { diff --git a/winsup/cygwin/include/cygwin/cygwin_dll.h b/winsup/cygwin/include/cygwin/cygwin_dll.h index 1e4cf98ba5..b77598bb63 100644 --- a/winsup/cygwin/include/cygwin/cygwin_dll.h +++ b/winsup/cygwin/include/cygwin/cygwin_dll.h @@ -24,8 +24,8 @@ details. */ CDECL_BEGIN \ int Entry (HINSTANCE h, DWORD reason, void *ptr); \ typedef int (*mainfunc) (int, char **, char **); \ - extern PVOID cygwin_attach_dll (HMODULE, mainfunc); \ - extern void cygwin_detach_dll (PVOID); \ + extern PVOID msys_attach_dll (HMODULE, mainfunc); \ + extern void msys_detach_dll (PVOID); \ CDECL_END \ \ static HINSTANCE storedHandle; \ @@ -42,7 +42,7 @@ static int __dllMain (int a __attribute__ ((__unused__)), \ \ static PVOID dll_index; \ \ -int _cygwin_dll_entry (HINSTANCE h, DWORD reason, void *ptr) \ +int _msys_dll_entry (HINSTANCE h, DWORD reason, void *ptr) \ { \ int ret; \ ret = 1; \ @@ -55,7 +55,7 @@ int _cygwin_dll_entry (HINSTANCE h, DWORD reason, void *ptr) \ storedReason = reason; \ storedPtr = ptr; \ __dynamically_loaded = (ptr == NULL); \ - dll_index = cygwin_attach_dll (h, &__dllMain); \ + dll_index = msys_attach_dll (h, &__dllMain); \ if (dll_index == (PVOID) -1) \ ret = 0; \ } \ @@ -66,7 +66,7 @@ int _cygwin_dll_entry (HINSTANCE h, DWORD reason, void *ptr) \ ret = Entry (h, reason, ptr); \ if (ret) \ { \ - cygwin_detach_dll (dll_index); \ + msys_detach_dll (dll_index); \ dll_index = (PVOID) -1; \ } \ } \ diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index fb821a681b..1c68287d9f 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -502,7 +502,11 @@ details. */ names include the CYGWIN_VERSION_SHARED_DATA version as well as this identifier. */ +#ifdef __MSYS__ +#define CYGWIN_VERSION_DLL_IDENTIFIER "msys-2.0" +#else #define CYGWIN_VERSION_DLL_IDENTIFIER "cygwin1" +#endif /* The Cygwin mount table interface in the Win32 registry also has a version number associated with it in case that is changed in a non-backwards @@ -518,7 +522,11 @@ details. */ /* Identifiers used in the Win32 registry. */ +#ifdef __MSYS__ +#define CYGWIN_INFO_CYGWIN_REGISTRY_NAME "MSYS" +#else #define CYGWIN_INFO_CYGWIN_REGISTRY_NAME "Cygwin" +#endif #define CYGWIN_INFO_INSTALLATIONS_NAME "Installations" /* The default cygdrive prefix. */ diff --git a/winsup/cygwin/lib/_cygwin_crt0_common.cc b/winsup/cygwin/lib/_cygwin_crt0_common.cc index d356a50fba..801b6f91ca 100644 --- a/winsup/cygwin/lib/_cygwin_crt0_common.cc +++ b/winsup/cygwin/lib/_cygwin_crt0_common.cc @@ -73,7 +73,11 @@ struct per_process_cxx_malloc __cygwin_cxx_malloc = and then jump to the dll. */ int +#ifdef __MSYS__ +_msys_crt0_common (MainFunc f, per_process *u) +#else _cygwin_crt0_common (MainFunc f, per_process *u) +#endif { per_process *newu = (per_process *) cygwin_internal (CW_USER_DATA); bool uwasnull; diff --git a/winsup/cygwin/lib/crt0.h b/winsup/cygwin/lib/crt0.h index e599b44934..e81750032b 100644 --- a/winsup/cygwin/lib/crt0.h +++ b/winsup/cygwin/lib/crt0.h @@ -13,7 +13,11 @@ extern "C" { #include "winlean.h" struct per_process; typedef int (*MainFunc) (int argc, char *argv[], char **env); +#ifdef __MSYS__ +int _msys_crt0_common (MainFunc, struct per_process *); +#else int _cygwin_crt0_common (MainFunc, struct per_process *); +#endif PVOID dll_dllcrt0 (HMODULE, struct per_process *); #ifdef __cplusplus diff --git a/winsup/cygwin/lib/cygwin_attach_dll.c b/winsup/cygwin/lib/cygwin_attach_dll.c index 866bfd80fa..82679c4a97 100644 --- a/winsup/cygwin/lib/cygwin_attach_dll.c +++ b/winsup/cygwin/lib/cygwin_attach_dll.c @@ -15,10 +15,18 @@ details. */ /* for a loaded dll */ PVOID +#ifdef __MSYS__ +msys_attach_dll (HMODULE h, MainFunc f) +#else cygwin_attach_dll (HMODULE h, MainFunc f) +#endif { static struct per_process u; +#ifdef __MSYS__ + (void) _msys_crt0_common (f, &u); +#else (void) _cygwin_crt0_common (f, &u); +#endif /* jump into the dll. */ return dll_dllcrt0 (h, &u); diff --git a/winsup/cygwin/lib/cygwin_crt0.c b/winsup/cygwin/lib/cygwin_crt0.c index 7020a639dd..396447e52e 100644 --- a/winsup/cygwin/lib/cygwin_crt0.c +++ b/winsup/cygwin/lib/cygwin_crt0.c @@ -14,8 +14,16 @@ extern void _dll_crt0 () /* for main module */ void +#ifdef __MSYS__ +msys_crt0 (MainFunc f) +#else cygwin_crt0 (MainFunc f) +#endif { +#ifdef __MSYS__ + _msys_crt0_common (f, NULL); +#else _cygwin_crt0_common (f, NULL); +#endif _dll_crt0 (); /* Jump into the dll, never to return */ } diff --git a/winsup/cygwin/local_includes/cygserver_setpwd.h b/winsup/cygwin/local_includes/cygserver_setpwd.h index fc1576b059..b2975111cf 100644 --- a/winsup/cygwin/local_includes/cygserver_setpwd.h +++ b/winsup/cygwin/local_includes/cygserver_setpwd.h @@ -12,7 +12,11 @@ details. */ #include #include "cygserver.h" +#ifdef __MSYS__ +#define CYGWIN_LSA_KEY_PREFIX L"L$MSYS_" +#else #define CYGWIN_LSA_KEY_PREFIX L"L$CYGWIN_" +#endif #ifndef __INSIDE_CYGWIN__ class transport_layer_base; diff --git a/winsup/cygwin/scripts/mkvers.sh b/winsup/cygwin/scripts/mkvers.sh index 38f439cd0d..a3d45c5db0 100755 --- a/winsup/cygwin/scripts/mkvers.sh +++ b/winsup/cygwin/scripts/mkvers.sh @@ -123,7 +123,7 @@ dir=$(echo $dir | sed -e 's%/include/cygwin.*$%%' -e 's%include/cygwin.*$%.%') ) | while read var; do read val cat <&9 @@ -135,9 +135,9 @@ trap "rm -f /tmp/mkvers.$$" 0 1 2 15 # cat <&9 #ifdef DEBUGGING - "%%% Cygwin shared id: " CYGWIN_VERSION_DLL_IDENTIFIER "S" shared_data_version "-$builddate\n" + "%%% MSYS shared id: " CYGWIN_VERSION_DLL_IDENTIFIER "S" shared_data_version "-$builddate\n" #else - "%%% Cygwin shared id: " CYGWIN_VERSION_DLL_IDENTIFIER "S" shared_data_version "\n" + "%%% MSYS shared id: " CYGWIN_VERSION_DLL_IDENTIFIER "S" shared_data_version "\n" #endif "END_CYGWIN_VERSION_INFO\n\0"; cygwin_version_info cygwin_version = diff --git a/winsup/cygwin/sec/auth.cc b/winsup/cygwin/sec/auth.cc index 43b5803893..db1d5c8977 100644 --- a/winsup/cygwin/sec/auth.cc +++ b/winsup/cygwin/sec/auth.cc @@ -462,7 +462,7 @@ verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern) if (!NT_SUCCESS (status)) debug_printf ("NtQueryInformationToken(), %y", status); else - *pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8); + *pintern = intern = !memcmp (ts.SourceName, "MSYS.2", 6); } /* Verify usersid */ cygsid tok_usersid (NO_SID); @@ -747,7 +747,7 @@ s4uauth (bool logon, PCWSTR domain, PCWSTR user, NTSTATUS &ret_status) { /* Register as logon process. */ debug_printf ("Impersonation requested"); - RtlInitAnsiString (&name, "Cygwin"); + RtlInitAnsiString (&name, "MSYS"); status = LsaRegisterLogonProcess (&name, &lsa_hdl, &sec_mode); } else @@ -786,11 +786,11 @@ s4uauth (bool logon, PCWSTR domain, PCWSTR user, NTSTATUS &ret_status) } /* Create origin. */ - stpcpy (origin.buf, "Cygwin"); + stpcpy (origin.buf, "MSYS"); RtlInitAnsiString (&origin.str, origin.buf); /* Create token source. */ - memcpy (ts.SourceName, "Cygwin.1", 8); + memcpy (ts.SourceName, "MSYS.2", 6); ts.SourceIdentifier.HighPart = 0; ts.SourceIdentifier.LowPart = kerberos_auth ? 0x0105 : 0x0106; diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 11033bca5e..2d7071bd6b 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -339,7 +339,7 @@ try_to_bin (path_conv &pc, HANDLE &fh, ACCESS_MASK access, ULONG flags) } else { - /* Create unique filename. Start with a dot, followed by "cyg" + /* Create unique filename. Start with a dot, followed by "msys" transposed to the Unicode private use area in the U+f700 area on file systems supporting Unicode (except Samba), followed by the inode number in hex, followed by a path hash in hex. The @@ -347,7 +347,7 @@ try_to_bin (path_conv &pc, HANDLE &fh, ACCESS_MASK access, ULONG flags) RtlAppendUnicodeToString (&recycler, (pc.fs_flags () & FILE_UNICODE_ON_DISK && !pc.fs_is_samba ()) - ? L".\xf763\xf779\xf767" : L".cyg"); + ? L".\xf76d\xf773\xf779\xf773" : L".msys"); pfii = (PFILE_INTERNAL_INFORMATION) infobuf; status = NtQueryInformationFile (fh, &io, pfii, sizeof *pfii, FileInternalInformation); diff --git a/winsup/cygwin/syslog.cc b/winsup/cygwin/syslog.cc index 6a295501f1..431f9d2396 100644 --- a/winsup/cygwin/syslog.cc +++ b/winsup/cygwin/syslog.cc @@ -26,7 +26,11 @@ details. */ #include "cygtls.h" #include "tls_pbuf.h" +#ifdef __MSYS__ +#define CYGWIN_LOG_NAME L"MSYS" +#else #define CYGWIN_LOG_NAME L"Cygwin" +#endif static struct { diff --git a/winsup/cygwin/winver.rc b/winsup/cygwin/winver.rc index 980d51204c..58878d41bd 100644 --- a/winsup/cygwin/winver.rc +++ b/winsup/cygwin/winver.rc @@ -35,7 +35,7 @@ BEGIN VALUE "InternalName", CYGWIN_DLL_NAME VALUE "LegalCopyright", "Copyright \251 Cygwin Authors 1996-" STRINGIFY(CYGWIN_BUILD_YEAR) VALUE "OriginalFilename", CYGWIN_DLL_NAME - VALUE "ProductName", "Cygwin" + VALUE "ProductName", "MSYS2" VALUE "ProductVersion", STRINGIFY(CYGWIN_VERSION) VALUE "APIVersion", CYGWIN_API_VERSION VALUE "SharedMemoryVersion", STRINGIFY(CYGWIN_VERSION_SHARED_DATA) diff --git a/winsup/testsuite/winsup.api/cygload.cc b/winsup/testsuite/winsup.api/cygload.cc index afd3ee90fc..1b2f79dc05 100644 --- a/winsup/testsuite/winsup.api/cygload.cc +++ b/winsup/testsuite/winsup.api/cygload.cc @@ -25,7 +25,7 @@ save for errors. -testinterrupts Pauses the program for 30 seconds so you can demonstrate that it handles ^C properly. - -cygwin Name of DLL to load. Defaults to "cygwin1.dll". */ + -cygwin Name of DLL to load. Defaults to "msys-2.0.dll". */ #include "cygload.h" #include @@ -154,13 +154,13 @@ cygwin::connector::connector (const char *dll) *out << "Initializing cygwin..." << endl; - // This calls dcrt0.cc:cygwin_dll_init(), which calls dll_crt0_1(), + // This calls dcrt0.cc:msys_dll_init(), which calls dll_crt0_1(), // which will, among other things: // * spawn the cygwin signal handling thread from sigproc_init() // * initialize the thread-local storage for this thread and overwrite // the first 4K of the stack void (*cyginit) (); - get_symbol ("cygwin_dll_init", cyginit); + get_symbol ("msys_dll_init", cyginit); (*cyginit) (); *out << "Loading symbols..." << endl; @@ -224,7 +224,7 @@ cygwin::connector::~connector () // This should call init.cc:dll_entry() with DLL_PROCESS_DETACH. if (!FreeLibrary (_library)) - throw windows_error ("FreeLibrary", "cygwin1.dll"); + throw windows_error ("FreeLibrary", "msys-2.0.dll"); } catch (std::exception &x) { @@ -490,7 +490,7 @@ main (int argc, char *argv[]) std::ostringstream output; bool verbose = false, testinterrupts = false; - const char *dll = "cygwin1.dll"; + const char *dll = "msys-2.0.dll"; out = &output; diff --git a/winsup/testsuite/winsup.api/cygload.h b/winsup/testsuite/winsup.api/cygload.h index 30154048b0..0f2aacda9a 100644 --- a/winsup/testsuite/winsup.api/cygload.h +++ b/winsup/testsuite/winsup.api/cygload.h @@ -76,7 +76,7 @@ namespace cygwin // spawns a thread to let you receive signals from cygwin. class connector { public: - connector (const char *dll = "cygwin1.dll"); + connector (const char *dll = "msys-2.0.dll"); ~connector (); // A wrapper around GetProcAddress() for fetching symbols from the diff --git a/winsup/utils/ldd.cc b/winsup/utils/ldd.cc index 0d073c2989..a31c4c6e44 100644 --- a/winsup/utils/ldd.cc +++ b/winsup/utils/ldd.cc @@ -249,7 +249,7 @@ tocyg (wchar_t *win_fn) return fn; } -#define CYGWIN_DLL_LEN (wcslen (L"\\cygwin1.dll")) +#define CYGWIN_DLL_LEN (wcslen (L"\\msys-2.0.dll")) static int print_dlls (dlls *dll, const wchar_t *dllfn, const wchar_t *process_fn) { diff --git a/winsup/utils/loadlib.h b/winsup/utils/loadlib.h index c83b76478f..42ffbfdc03 100644 --- a/winsup/utils/loadlib.h +++ b/winsup/utils/loadlib.h @@ -13,7 +13,7 @@ #include /* Load all system libs from the windows system directory by prepending the - full path. This doesn't work for loadling cygwin1.dll. For this case, + full path. This doesn't work for loadling msys-2.0.dll. For this case, instead of prepending the path, make sure that the CWD is removed from the DLL search path, if possible (XP SP1++, Vista++). */ static HMODULE _load_sys_library (const wchar_t *dll) __attribute__ ((used)); @@ -45,8 +45,8 @@ _load_sys_library (const wchar_t *dll) set_dll_directory (L""); } - if (wcscmp (dll, L"cygwin1.dll") == 0) - return LoadLibraryExW (L"cygwin1.dll", NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (wcscmp (dll, L"msys-2.0.dll") == 0) + return LoadLibraryExW (L"msys-2.0.dll", NULL, LOAD_WITH_ALTERED_SEARCH_PATH); wcscpy (dllpath, sysdir); wcscpy (dllpath + sysdir_len, dll); diff --git a/winsup/utils/mingw/cygcheck.cc b/winsup/utils/mingw/cygcheck.cc index 1dde2ecbab..7718ab9dc9 100644 --- a/winsup/utils/mingw/cygcheck.cc +++ b/winsup/utils/mingw/cygcheck.cc @@ -95,8 +95,7 @@ static const char *known_env_vars[] = { "c_include_path", "compiler_path", "cxx_include_path", - "cygwin", - "cygwin32", + "msys", "dejagnu", "expect", "gcc_default_options", @@ -554,7 +553,7 @@ struct ImpDirectory static bool track_down (const char *file, const char *suffix, int lvl); -#define CYGPREFIX (sizeof ("%%% Cygwin ") - 1) +#define CYGPREFIX (sizeof ("%%% Msys ") - 1) static void cygwin_info (HANDLE h) { @@ -586,7 +585,7 @@ cygwin_info (HANDLE h) while (buf < bufend) if ((buf = (char *) memchr (buf, '%', bufend - buf)) == NULL) break; - else if (strncmp ("%%% Cygwin ", buf, CYGPREFIX) != 0) + else if (strncmp ("%%% Msys ", buf, CYGPREFIX) != 0) buf++; else { @@ -780,7 +779,7 @@ dll_info (const char *path, HANDLE fh, int lvl, int recurse) } } } - if (strstr (path, "\\cygwin1.dll")) + if (strstr (path, "\\msys-2.0.dll")) cygwin_info (fh); } @@ -1027,7 +1026,7 @@ scan_registry (RegInfo * prev, HKEY hKey, char *name, int cygwin, bool wow64) char *cp; for (cp = name; *cp; cp++) - if (strncasecmp (cp, "Cygwin", 6) == 0) + if (strncasecmp (cp, "Msys", 4) == 0) cygwin = 1; DWORD num_subkeys, max_subkey_len, num_values; @@ -1309,7 +1308,7 @@ handle_reg_installation (handle_reg_t what) printf ("Cygwin installations found in the registry:\n"); for (int i = 0; i < 2; ++i) if (RegOpenKeyEx (i ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, - "SOFTWARE\\Cygwin\\Installations", 0, + "SOFTWARE\\Msys\\Installations", 0, what == DELETE_KEY ? KEY_READ | KEY_WRITE : KEY_READ, &key) == ERROR_SUCCESS) @@ -1331,7 +1330,7 @@ handle_reg_installation (handle_reg_t what) if (what == PRINT_KEY) printf (" %s Key: %s Path: %s", i ? "User: " : "System:", name, path); - strcat (path, "\\bin\\cygwin1.dll"); + strcat (path, "\\bin\\msys-2.0.dll"); if (what == PRINT_KEY) printf ("%s\n", access (path, F_OK) ? " (ORPHANED)" : ""); else if (access (path, F_OK)) @@ -1783,7 +1782,7 @@ dump_sysinfo () if (registry) { if (givehelp) - printf ("Scanning registry for keys with 'Cygwin' in them...\n"); + printf ("Scanning registry for keys with 'Msys' in them...\n"); scan_registry (0, HKEY_CURRENT_USER, (char *) "HKEY_CURRENT_USER", 0, false); scan_registry (0, HKEY_LOCAL_MACHINE, @@ -1978,10 +1977,10 @@ dump_sysinfo () wcstombs (f, ffinfo.cFileName, sizeof f); if (strcasecmp (f + strlen (f) - 4, ".dll") == 0) { - if (strncasecmp (f, "cyg", 3) == 0) + if (strncasecmp (f, "msys-", 5) == 0) { sprintf (tmp, "%s%s", pth->dir, f); - if (strcasecmp (f, "cygwin1.dll") == 0) + if (strcasecmp (f, "msys-2.0.dll") == 0) { if (!cygwin_dll_count) strcpy (cygdll_path, pth->dir); @@ -2005,9 +2004,9 @@ dump_sysinfo () FindClose (ff); } if (cygwin_dll_count > 1) - puts ("Warning: There are multiple cygwin1.dlls on your path"); + puts ("Warning: There are multiple msys-2.0.dlls on your path"); if (!cygwin_dll_count) - puts ("Warning: cygwin1.dll not found on your path"); + puts ("Warning: msys-2.0.dll not found on your path"); dump_dodgy_apps (verbose); @@ -3021,7 +3020,7 @@ load_cygwin (int& argc, char **&argv) { HMODULE h; - if (!(h = LoadLibrary ("cygwin1.dll"))) + if (!(h = LoadLibrary ("msys-2.0.dll"))) return; GetModuleFileNameW (h, cygwin_dll_path, 32768); if ((cygwin_internal = (uintptr_t (*) (cygwin_getinfo_types, ...)) diff --git a/winsup/utils/mingw/strace.cc b/winsup/utils/mingw/strace.cc index c220643b33..29db640239 100644 --- a/winsup/utils/mingw/strace.cc +++ b/winsup/utils/mingw/strace.cc @@ -284,7 +284,7 @@ load_cygwin () if (h) return 0; - if (!(h = LoadLibrary ("cygwin1.dll"))) + if (!(h = LoadLibrary ("msys-2.0.dll"))) { errno = ENOENT; return 0; @@ -354,17 +354,16 @@ create_child (char **argv) make_command_line (one_line, argv); SetConsoleCtrlHandler (NULL, 0); - - const char *cygwin_env = getenv ("CYGWIN"); + const char *cygwin_env = getenv ("MSYS"); const char *space; if (cygwin_env && strlen (cygwin_env) <= 256) /* sanity check */ space = " "; else space = cygwin_env = ""; - char *newenv = (char *) malloc (sizeof ("CYGWIN=noglob") + char *newenv = (char *) malloc (sizeof ("MSYS=noglob") + strlen (space) + strlen (cygwin_env)); - sprintf (newenv, "CYGWIN=noglob%s%s", space, cygwin_env); + sprintf (newenv, "MSYS=noglob%s%s", space, cygwin_env); _putenv (newenv); ret = CreateProcess (0, one_line.buf, /* command line */ NULL, /* Security */ diff --git a/winsup/utils/path.cc b/winsup/utils/path.cc index fe55a646d9..323e4c784b 100644 --- a/winsup/utils/path.cc +++ b/winsup/utils/path.cc @@ -585,14 +585,14 @@ read_mounts () } max_mount_entry = 0; - /* First fetch the cygwin1.dll path from the LoadLibrary call in load_cygwin. - This utilizes the DLL search order to find a matching cygwin1.dll and to + /* First fetch the msys-2.0.dll path from the LoadLibrary call in load_cygwin. + This utilizes the DLL search order to find a matching msys-2.0.dll and to compute the installation path from that DLL's path. */ if (cygwin_dll_path[0]) wcscpy (path, cygwin_dll_path); - /* If we can't load cygwin1.dll, check where cygcheck is living itself and - try to fetch installation path from here. Does cygwin1.dll exist in the - same path? This should only kick in if the cygwin1.dll in the same path + /* If we can't load msys-2.0.dll, check where cygcheck is living itself and + try to fetch installation path from here. Does msys-2.0.dll exist in the + same path? This should only kick in if the msys-2.0.dll in the same path has been made non-executable for the current user accidentally. */ else if (!GetModuleFileNameW (NULL, path, 32768)) return; @@ -601,7 +601,7 @@ read_mounts () { if (!cygwin_dll_path[0]) { - wcscpy (path_end, L"\\cygwin1.dll"); + wcscpy (path_end, L"\\msys-2.0.dll"); DWORD attr = GetFileAttributesW (path); if (attr == (DWORD) -1 || (attr & (FILE_ATTRIBUTE_DIRECTORY diff --git a/winsup/utils/ssp.c b/winsup/utils/ssp.c index 96a90a1d98..95045e1e8b 100644 --- a/winsup/utils/ssp.c +++ b/winsup/utils/ssp.c @@ -710,15 +710,15 @@ usage (FILE * stream) "You must specify the range of memory addresses to keep track of\n" "manually, but it's not hard to figure out what to specify. Use the\n" "\"objdump\" program to determine the bounds of the target's \".text\"\n" - "section. Let's say we're profiling cygwin1.dll. Make sure you've\n" + "section. Let's say we're profiling msys-2.0.dll. Make sure you've\n" "built it with debug symbols (else gprof won't run) and run objdump\n" "like this:\n" "\n" - " objdump -h cygwin1.dll\n" + " objdump -h msys-2.0.dll\n" "\n" "It will print a report like this:\n" "\n" - "cygwin1.dll: file format pei-i386\n" + "msys-2.0.dll: file format pei-i386\n" "\n" "Sections:\n" "Idx Name Size VMA LMA File off Algn\n" @@ -749,7 +749,7 @@ usage (FILE * stream) "\"gmon.out\". You can turn this data file into a readable report with\n" "gprof:\n" "\n" - " gprof -b cygwin1.dll\n" + " gprof -b msys-2.0.dll\n" "\n" "The \"-b\" means 'skip the help pages'. You can omit this until you're\n" "familiar with the report layout. The gprof documentation explains\n" From d076660c2d88cc79897b73b53134b040d623c547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 21:17:46 +0300 Subject: [PATCH 059/116] Add functionality for converting UNIX paths in arguments and environment variables to Windows form for native Win32 applications. --- winsup/cygwin/Makefile.am | 1 + winsup/cygwin/environ.cc | 24 +- winsup/cygwin/external.cc | 2 +- winsup/cygwin/include/sys/cygwin.h | 6 + winsup/cygwin/local_includes/environ.h | 2 +- winsup/cygwin/local_includes/winf.h | 4 + winsup/cygwin/msys2_path_conv.cc | 699 +++++++++++++++++++++++++ winsup/cygwin/msys2_path_conv.h | 147 ++++++ winsup/cygwin/path.cc | 69 +++ winsup/cygwin/spawn.cc | 38 +- 10 files changed, 988 insertions(+), 4 deletions(-) create mode 100644 winsup/cygwin/msys2_path_conv.cc create mode 100644 winsup/cygwin/msys2_path_conv.h diff --git a/winsup/cygwin/Makefile.am b/winsup/cygwin/Makefile.am index e65e675bcd..b1b0df708e 100644 --- a/winsup/cygwin/Makefile.am +++ b/winsup/cygwin/Makefile.am @@ -312,6 +312,7 @@ DLL_FILES= \ miscfuncs.cc \ mktemp.cc \ msg.cc \ + msys2_path_conv.cc \ mount.cc \ net.cc \ netdb.cc \ diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index d4cedcbdfe..639e69393b 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -1046,7 +1046,7 @@ env_compare (const void *key, const void *memb) to the child. */ char ** build_env (const char * const *envp, PWCHAR &envblock, int &envc, - bool no_envblock, HANDLE new_token) + bool no_envblock, HANDLE new_token, bool keep_posix) { PWCHAR cwinenv = NULL; size_t winnum = 0; @@ -1139,6 +1139,19 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, for (srcp = envp, dstp = newenv, pass_dstp = pass_env; *srcp; srcp++) { bool calc_tl = !no_envblock; +#ifdef __MSYS__ + /* Don't pass timezone environment to non-msys applications */ + if (!keep_posix && ascii_strncasematch(*srcp, "TZ=", 3)) + { + const char *v = *srcp + 3; + if (*v == ':') + goto next1; + for (; *v; v++) + if (!isalpha(*v) && !isdigit(*v) && + *v != '-' && *v != '+' && *v != ':') + goto next1; + } +#endif /* Look for entries that require special attention */ for (unsigned i = 0; i < SPENVS_SIZE; i++) if (!saw_spenv[i] && (*dstp = spenvs[i].retrieve (no_envblock, *srcp))) @@ -1259,6 +1272,15 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, saw_PATH = true; } } +#ifdef __MSYS__ + else if (!keep_posix) { + char *win_arg = arg_heuristic(*srcp); + debug_printf("WIN32_PATH is %s", win_arg); + p = cstrdup1(win_arg); + if (win_arg != *srcp) + free (win_arg); + } +#endif else p = *srcp; /* Don't worry about it */ diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc index 97e4528741..33863d8001 100644 --- a/winsup/cygwin/external.cc +++ b/winsup/cygwin/external.cc @@ -141,7 +141,7 @@ create_winenv (const char * const *env) int unused_envc; PWCHAR envblock = NULL; char **envp = build_env (env ?: environ, envblock, unused_envc, false, - NULL); + NULL, true); PWCHAR p = envblock; if (envp) diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h index 2c5997b5e2..6383646cc7 100644 --- a/winsup/cygwin/include/sys/cygwin.h +++ b/winsup/cygwin/include/sys/cygwin.h @@ -60,6 +60,12 @@ extern ssize_t cygwin_conv_path_list (cygwin_conv_path_t what, const void *from, to one of the above values, or to ENOMEM if malloc fails. */ extern void *cygwin_create_path (cygwin_conv_path_t what, const void *from); +extern char * arg_heuristic_with_exclusions (char const * const arg, + char const * exclusions, + size_t exclusions_count); + +extern char * arg_heuristic (char const * const); + extern pid_t cygwin_winpid_to_pid (int); extern int cygwin_posix_path_list_p (const char *); extern void cygwin_split_path (const char *, char *, char *); diff --git a/winsup/cygwin/local_includes/environ.h b/winsup/cygwin/local_includes/environ.h index 86e64a72f9..0dd45359cc 100644 --- a/winsup/cygwin/local_includes/environ.h +++ b/winsup/cygwin/local_includes/environ.h @@ -34,7 +34,7 @@ win_env *getwinenv (const char *name, const char *posix = NULL, win_env * = NULL char *getwinenveq (const char *name, size_t len, int); char **build_env (const char * const *envp, PWCHAR &envblock, - int &envc, bool need_envblock, HANDLE new_token); + int &envc, bool need_envblock, HANDLE new_token, bool keep_posix); char **win32env_to_cygenv (PWCHAR rawenv, bool posify); diff --git a/winsup/cygwin/local_includes/winf.h b/winsup/cygwin/local_includes/winf.h index b586934410..bc53cd1aa3 100644 --- a/winsup/cygwin/local_includes/winf.h +++ b/winsup/cygwin/local_includes/winf.h @@ -56,6 +56,10 @@ class av calloced = 1; } } + void replace (int i, const char *arg) + { + argv[i] = cstrdup1 (arg); + } void dup_all () { for (int i = calloced; i < argc; i++) diff --git a/winsup/cygwin/msys2_path_conv.cc b/winsup/cygwin/msys2_path_conv.cc new file mode 100644 index 0000000000..c52728759e --- /dev/null +++ b/winsup/cygwin/msys2_path_conv.cc @@ -0,0 +1,699 @@ +/* + The MSYS2 Path conversion source code is licensed under: + + CC0 1.0 Universal + + Official translations of this legal tool are available + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + + Statement of Purpose + + The laws of most jurisdictions throughout the world automatically + confer exclusive Copyright and Related Rights (defined below) upon the + creator and subsequent owner(s) (each and all, an "owner") of an + original work of authorship and/or a database (each, a "Work"). + + Certain owners wish to permanently relinquish those rights to a Work + for the purpose of contributing to a commons of creative, cultural and + scientific works ("Commons") that the public can reliably and without + fear of later claims of infringement build upon, modify, incorporate + in other works, reuse and redistribute as freely as possible in any + form whatsoever and for any purposes, including without limitation + commercial purposes. These owners may contribute to the Commons to + promote the ideal of a free culture and the further production of + creative, cultural and scientific works, or to gain reputation or + greater distribution for their Work in part through the use and + efforts of others. + + For these and/or other purposes and motivations, and without any + expectation of additional consideration or compensation, the person + associating CC0 with a Work (the "Affirmer"), to the extent that he or + she is an owner of Copyright and Related Rights in the Work, + voluntarily elects to apply CC0 to the Work and publicly distribute + the Work under its terms, with knowledge of his or her Copyright and + Related Rights in the Work and the meaning and intended legal effect + of CC0 on those rights. + + 1. Copyright and Related Rights. A Work made available under CC0 may + be protected by copyright and related or neighboring rights + ("Copyright and Related Rights"). Copyright and Related Rights + include, but are not limited to, the following: + + the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + moral rights retained by the original author(s) and/or performer(s); + publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + rights protecting the extraction, dissemination, use and reuse of data + in a Work; + database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and + other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations + thereof. + + 2. Waiver. To the greatest extent permitted by, but not in + contravention of, applicable law, Affirmer hereby overtly, fully, + permanently, irrevocably and unconditionally waives, abandons, and + surrenders all of Affirmer's Copyright and Related Rights and + associated claims and causes of action, whether now known or unknown + (including existing as well as future claims and causes of action), in + the Work (i) in all territories worldwide, (ii) for the maximum + duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number + of copies, and (iv) for any purpose whatsoever, including without + limitation commercial, advertising or promotional purposes (the + "Waiver"). Affirmer makes the Waiver for the benefit of each member of + the public at large and to the detriment of Affirmer's heirs and + successors, fully intending that such Waiver shall not be subject to + revocation, rescission, cancellation, termination, or any other legal + or equitable action to disrupt the quiet enjoyment of the Work by the + public as contemplated by Affirmer's express Statement of Purpose. + + 3. Public License Fallback. Should any part of the Waiver for any + reason be judged legally invalid or ineffective under applicable law, + then the Waiver shall be preserved to the maximum extent permitted + taking into account Affirmer's express Statement of Purpose. In + addition, to the extent the Waiver is so judged Affirmer hereby grants + to each affected person a royalty-free, non transferable, non + sublicensable, non exclusive, irrevocable and unconditional license to + exercise Affirmer's Copyright and Related Rights in the Work (i) in + all territories worldwide, (ii) for the maximum duration provided by + applicable law or treaty (including future time extensions), (iii) in + any current or future medium and for any number of copies, and (iv) + for any purpose whatsoever, including without limitation commercial, + advertising or promotional purposes (the "License"). The License shall + be deemed effective as of the date CC0 was applied by Affirmer to the + Work. Should any part of the License for any reason be judged legally + invalid or ineffective under applicable law, such partial invalidity + or ineffectiveness shall not invalidate the remainder of the License, + and in such case Affirmer hereby affirms that he or she will not (i) + exercise any of his or her remaining Copyright and Related Rights in + the Work or (ii) assert any associated claims and causes of action + with respect to the Work, in either case contrary to Affirmer's + express Statement of Purpose. + + 4. Limitations and Disclaimers. + + No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. + + Contributions thanks to: + niXman + Ely Arzhannikov + Alexey Pavlov + Ray Donnelly + Johannes Schindelin + +*/ + +#include "winsup.h" +#include "miscfuncs.h" +#include +#include +#include +#include +#include +#include "cygerrno.h" +#include "security.h" +#include "path.h" +#include "fhandler.h" +#include "dtable.h" +#include "cygheap.h" +#include "shared_info.h" +#include "cygtls.h" +#include "tls_pbuf.h" +#include "environ.h" +#include +#include +#include +#include + +#include "msys2_path_conv.h" + +typedef enum PATH_TYPE_E { + NONE = 0, + SIMPLE_WINDOWS_PATH, + ESCAPE_WINDOWS_PATH, + WINDOWS_PATH_LIST, + UNC, + ESCAPED_PATH, + ROOTED_PATH, + POSIX_PATH_LIST, + RELATIVE_PATH, + URL +} path_type; + +int is_special_posix_path(const char* from, const char* to, char** dst, const char* dstend); +void posix_to_win32_path(const char* from, const char* to, char** dst, const char* dstend); + + +path_type find_path_start_and_type(const char** src, int recurse, const char* end); +void copy_to_dst(const char* from, const char* to, char** dst, const char* dstend); +void convert_path(const char** from, const char* to, path_type type, char** dst, const char* dstend); + +//Transformations +//SIMPLE_WINDOWS_PATH converter. Copy as is. Hold C:\Something\like\this +void swp_convert(const char** from, const char* to, char** dst, const char* dstend); +//ESCAPE_WINDOWS_PATH converter. Turn backslashes to slashes and skip first /. Hold /C:\Somethind\like\this +void ewp_convert(const char** from, const char* to, char** dst, const char* dstend); +//WINDOWS_PATH_LIST converter. Copy as is. Hold /something/like/this; +void wpl_convert(const char** from, const char* to, char** dst, const char* dstend); +//UNC convert converter. Copy as is. Hold //somethig/like/this +void unc_convert(const char** from, const char* to, char** dst, const char* dstend); +//ESCAPED_PATH converter. Turn backslashes to slashes and skip first /. Hold //something\like\this +void ep_convert(const char** from, const char* to, char** dst, const char* dstend); +//ROOTED_PATH converter. Prepend root dir to front. Hold /something/like/this +void rp_convert(const char** from, const char* to, char** dst, const char* dstend); +//URL converter. Copy as is. +void url_convert(const char** from, const char* to, char** dst, const char* dstend); +//POSIX_PATH_LIST. Hold x::x/y:z +void ppl_convert(const char** from, const char* to, char** dst, const char* dstend); + + +void find_end_of_posix_list(const char** to, int* in_string) { + for (; **to != '\0' && (!in_string || **to != *in_string); ++*to) { + } + + if (**to == *in_string) { + *in_string = 0; + } +} + +void find_end_of_rooted_path(const char** from, const char** to, int* in_string) { + for (const char* it = *from; *it != '\0' && it != *to; ++it) + if (*it == '.' && *(it + 1) == '.' && *(it - 1) == '/') { + *to = it - 1; + return; + } + + for (; **to != '\0'; ++*to) { + if (*in_string == 0 && **to == ' ') { + return; + } + + if (**to == *in_string) { + *in_string = 0; + return; + } + + if (**to == '/') { + if (*(*to - 1) == ' ') { + *to -= 1; + return; + } + } + } +} + +void sub_convert(const char** from, const char** to, char** dst, const char* dstend, int* in_string) { + const char* copy_from = *from; + path_type type = find_path_start_and_type(from, false, *to); + debug_printf("found type %d for path %s", type, copy_from); + + if (type == POSIX_PATH_LIST) { + find_end_of_posix_list(to, in_string); + } + + if (type == ROOTED_PATH) { + find_end_of_rooted_path(from, to, in_string); + } + + copy_to_dst(copy_from, *from, dst, dstend); + + if (type != NONE) { + convert_path(from, *to, type, dst, dstend); + } + + if (*dst != dstend) { + **dst = **to; + *dst += 1; + } +} + +const char* convert(char *dst, size_t dstlen, const char *src) { + if (dst == NULL || dstlen == 0 || src == NULL) { + return dst; + } + + int need_convert = false; + for (const char* it = src; *it != '\0'; ++it) { + if (*it == '\\' || *it == '/') { + need_convert = true; + break; + } + if (isspace(*it)) { + need_convert = false; + break; + } + } + + char* dstit = dst; + char* dstend = dst + dstlen; + if (!need_convert) { + copy_to_dst(src, NULL, &dstit, dstend); + *dstit = '\0'; + return dst; + } + *dstend = '\0'; + + const char* srcit = src; + const char* srcbeg = src; + + int in_string = false; + + for (; *srcit != '\0'; ++srcit) { + if (*srcit == '\'' || *srcit == '"') { + if (in_string == *srcit) { + if (*(srcit + 1) != in_string) { + in_string = 0; + } + } else { + in_string = *srcit; + } + continue; + } + } + + sub_convert(&srcbeg, &srcit, &dstit, dstend, &in_string); + if (!*srcit) { + *dstit = '\0'; + return dst; + } + srcbeg = srcit + 1; + for (; *srcit != '\0'; ++srcit) { + continue; + } + copy_to_dst(srcbeg, srcit, &dstit, dstend); + *dstit = '\0'; + + /*if (dstit - dst < 2) { + dstit = dst; + copy_to_dst(src, NULL, &dstit, dstend); + *dstit = '\0'; + }*/ + + return dst; +} + +void copy_to_dst(const char* from, const char* to, char** dst, const char* dstend) { + for (; (*from != '\0') && (from != to) && (*dst != dstend); ++from, ++(*dst)) { + **dst = *from; + } +} + +const char** move(const char** p, int count) { + *p += count; + return p; +} + +path_type find_path_start_and_type(const char** src, int recurse, const char* end) { + const char* it = *src; + + if (*it == '\0' || it == end) return NONE; + + /* Let's not convert ~/.file to ~C:\msys64\.file */ + if (*it == '~') { +skip_p2w: + *src = end; + return NONE; + } + + /* + * Prevent Git's :file.txt and :/message syntax from beeing modified. + */ + if (*it == ':') + goto skip_p2w; + + while (it != end && *it) { + switch (*it) { + case '`': + case '\'': + case '*': + case '?': + case '[': + case ']': + goto skip_p2w; + case '/': + if (it + 1 < end && it[1] == '~') + goto skip_p2w; + break; + case ':': + // Avoid mangling IPv6 addresses + if (it + 1 < end && it[1] == ':') + goto skip_p2w; + + // Leave Git's :./name syntax alone + if (it + 1 < end && it[1] == '.') { + if (it + 2 < end && it[2] == '/') + goto skip_p2w; + if (it + 3 < end && it[2] == '.' && it[3] == '/') + goto skip_p2w; + } + break; + case '@': + // Paths do not contain '@@' + if (it + 1 < end && it[1] == '@') + goto skip_p2w; + } + ++it; + } + it = *src; + + while (!isalnum(*it) && *it != '/' && *it != '\\' && *it != ':' && *it != '-' && *it != '.') { + recurse = true; + it = ++*src; + if (it == end || *it == '\0') return NONE; + } + + path_type result = NONE; + + if (it + 1 == end) { + switch (*it) { + case '/': return ROOTED_PATH ; + default: return SIMPLE_WINDOWS_PATH; + } + } + + if (isalpha(*it) && *(it + 1) == ':') { + if (*(it + 2) == '\\') { + return SIMPLE_WINDOWS_PATH; + } + + if (*(it + 2) == '/' && memchr(it + 2, ':', end - (it + 2)) == NULL) { + return SIMPLE_WINDOWS_PATH; + } + + if (*(it + 2) == '/' && memchr(it + 2, ';', end - (it + 2))) { + return WINDOWS_PATH_LIST; + } + } + + if (*it == '.' && (*(it + 1) == '.' || *(it + 1) == '/') && memchr(it + 2, ':', end - (it + 2)) == NULL) { + return RELATIVE_PATH; + } + + if (*it == '/') { + it += 1; + + if (isalpha(*it) && *(it + 1) == ':') { + return ESCAPE_WINDOWS_PATH; + } + + if (*it == '.' && *(it + 1) == '.') { + return SIMPLE_WINDOWS_PATH; + } + + if (*it == '/') { + it += 1; + switch(*it) { + case ':': return URL; + case '/': return ESCAPED_PATH; + } + if (memchr(it, '/', end - it)) + return UNC; + else + return ESCAPED_PATH; + } + + for (; *it != '\0' && it != end; ++it) { + switch(*it) { + case ':': {char ch = *(it + 1); if (ch == '/' || ch == ':' || ch == '.') return POSIX_PATH_LIST;} return WINDOWS_PATH_LIST; + case ';': return WINDOWS_PATH_LIST; + } + } + + if (result != NONE) { + return result; + } + + return ROOTED_PATH; + } + + int starts_with_minus = 0; + int starts_with_minus_alpha = 0; + int only_dots = *it == '.'; + int has_slashes = 0; + if (*it == '-') { + starts_with_minus = 1; + it += 1; + if (isalpha(*it)) { + it += 1; + starts_with_minus_alpha = 1; + if (memchr(it, ';', end - it)) { + return WINDOWS_PATH_LIST; + } + } + } + + for (const char* it2 = it; *it2 != '\0' && it2 != end; ++it2) { + char ch = *it2; + if (starts_with_minus_alpha) { + if (isalpha(ch) && (*(it2+1) == ':') && (*(it2+2) == '/')) { + return SIMPLE_WINDOWS_PATH; + } + if (ch == '/'&& memchr(it2, ',', end - it2) == NULL) { + *src = it2; + return find_path_start_and_type(src, true, end); + } + starts_with_minus_alpha = 0; + } + if (ch == '\'' || ch == '"') + starts_with_minus = false; + if ((ch == '=') || (ch == ':' && starts_with_minus) || ((ch == '\'' || ch == '"') && result == NONE)) { + *src = it2 + 1; + return find_path_start_and_type(src, true, end); + } + + if (ch == ',' && starts_with_minus) { + *src = it2 + 1; + return find_path_start_and_type(src, true, end); + } + + if (ch == ':' && it2 + 1 != end) { + it2 += 1; + ch = *it2; + if (ch == '/' || ch == ':' || ch == '.') { + if (ch == '/' && *(it2 + 1) == '/') { + return URL; + } else { + if (!only_dots && !has_slashes) + goto skip_p2w; + return POSIX_PATH_LIST; + } + } else if (memchr(it2, '=', end - it2) == NULL) { + return SIMPLE_WINDOWS_PATH; + } + } else if (ch != '.') { + only_dots = 0; + if (ch == '/' || ch == '\\') + has_slashes = 1; + } + } + + if (result != NONE) { + *src = it; + return result; + } + + return SIMPLE_WINDOWS_PATH; +} + +void convert_path(const char** from, const char* to, path_type type, char** dst, const char* dstend) { + switch(type) { + case SIMPLE_WINDOWS_PATH: swp_convert(from, to, dst, dstend); break; + case ESCAPE_WINDOWS_PATH: ewp_convert(from, to, dst, dstend); break; + case WINDOWS_PATH_LIST: wpl_convert(from, to, dst, dstend); break; + case RELATIVE_PATH: swp_convert(from, to, dst, dstend); break; + case UNC: unc_convert(from, to, dst, dstend); break; + case ESCAPED_PATH: ep_convert(from, to, dst, dstend); break; + case ROOTED_PATH: rp_convert(from, to, dst, dstend); break; + case URL: url_convert(from, to, dst, dstend); break; + case POSIX_PATH_LIST: ppl_convert(from, to, dst, dstend); break; + case NONE: // prevent warnings; + default: + return; + } +} + +void swp_convert(const char** from, const char* to, char** dst, const char* dstend) { + copy_to_dst(*from, to, dst, dstend); +} + +void ewp_convert(const char** from, const char* to, char** dst, const char* dstend) { + *from += 1; + unc_convert(from, to, dst, dstend); +} + +void wpl_convert(const char** from, const char* to, char** dst, const char* dstend) { + swp_convert(from, to, dst, dstend); +} + +void unc_convert(const char** from, const char* to, char** dst, const char* dstend) { + const char* it = *from; + for (; (*it != '\0' && it != to) && (*dst != dstend); ++it, ++(*dst)) { + if (*it == '\\') { + **dst = '/'; + } else { + **dst = *it; + } + } +} + +void ep_convert(const char** from, const char* to, char** dst, const char* dstend) { + ewp_convert(from, to, dst, dstend); +} + +void rp_convert(const char** from, const char* to, char** dst, const char* dstend) { + const char* it = *from; + const char* real_to = to; + + if (*real_to == '\0') { + real_to -= 1; + if (*real_to != '\'' && *real_to != '"') { + real_to += 1; + } + } + + if (!is_special_posix_path(*from, real_to, dst, dstend)) { + posix_to_win32_path(it, real_to, dst, dstend); + } + + if (*dst != dstend && real_to != to) { + **dst = *real_to; + *dst += 1; + } +} + +void url_convert(const char** from, const char* to, char** dst, const char* dstend) { + unc_convert(from, to, dst, dstend); +} + +void subp_convert(const char** from, const char* end, int is_url, char** dst, const char* dstend) { + const char* begin = *from; + path_type type = is_url ? URL : find_path_start_and_type(from, 0, end); + copy_to_dst(begin, *from, dst, dstend); + + if (type == NONE) { + return; + } + + char* start = *dst; + convert_path(from, end, type, dst, dstend); + + if (!is_url) { + for (; start != *dst; ++start) { + if (*start == '/') { + *start = '\\'; + } + } + } +} + +void ppl_convert(const char** from, const char* to, char** dst, const char* dstend) { + const char *orig_dst = *dst; + const char* it = *from; + const char* beg = it; + int prev_was_simc = 0; + int is_url = 0; + for (; (*it != '\0' && it != to) && (*dst != dstend); ++it) { + if (*it == ':') { + if (prev_was_simc) { + continue; + } + if (*(it + 1) == '/' && *(it + 2) == '/' && isalpha(*beg)) { + is_url = 1; + /* double-check: protocol must be alnum (or +) */ + for (const char *p = beg; p != it; ++p) + if (!isalnum(*p) && *p != '+') { + is_url = 0; + break; + } + if (is_url) + continue; + } + prev_was_simc = 1; + subp_convert(&beg, it, is_url, dst, dstend); + is_url = 0; + + if (*dst == dstend) { + system_printf("Path cut off during conversion: %s\n", orig_dst); + break; + } + + **dst = ';'; + *dst += 1; + } + + if (*it != ':' && prev_was_simc) { + prev_was_simc = 0; + beg = it; + } + } + + if (!prev_was_simc) { + subp_convert(&beg, it, is_url, dst, dstend); + } +} + +int is_special_posix_path(const char* from, const char* to, char** dst, const char* dstend) { + const char dev_null[] = "/dev/null"; + + if ((to - from) == (sizeof(dev_null) - 1) && strncmp(from, "/dev/null", to - from) == 0) { + copy_to_dst("nul", NULL, dst, dstend); + return true; + } + return false; +} + +void posix_to_win32_path(const char* from, const char* to, char** dst, const char* dstend) { + if ( from != to ) { + tmp_pathbuf tp; + char *one_path = tp.c_get(); + strncpy(one_path, from, to-from); + one_path[to-from] = '\0'; + + path_conv conv (one_path, 0); + if (conv.error) + { + set_errno(conv.error); + copy_to_dst(one_path, NULL, dst, dstend); + } else { + char* win32_path = tp.c_get(); + stpcpy (win32_path, conv.get_win32 ()); + for (; (*win32_path != '\0') && (*dst != dstend); ++win32_path, ++(*dst)) { + **dst = (*win32_path == '\\') ? '/' : *win32_path; + } + } + } +} + diff --git a/winsup/cygwin/msys2_path_conv.h b/winsup/cygwin/msys2_path_conv.h new file mode 100644 index 0000000000..67d85ecb64 --- /dev/null +++ b/winsup/cygwin/msys2_path_conv.h @@ -0,0 +1,147 @@ +/* + The MSYS2 Path conversion source code is licensed under: + + CC0 1.0 Universal + + Official translations of this legal tool are available + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + + Statement of Purpose + + The laws of most jurisdictions throughout the world automatically + confer exclusive Copyright and Related Rights (defined below) upon the + creator and subsequent owner(s) (each and all, an "owner") of an + original work of authorship and/or a database (each, a "Work"). + + Certain owners wish to permanently relinquish those rights to a Work + for the purpose of contributing to a commons of creative, cultural and + scientific works ("Commons") that the public can reliably and without + fear of later claims of infringement build upon, modify, incorporate + in other works, reuse and redistribute as freely as possible in any + form whatsoever and for any purposes, including without limitation + commercial purposes. These owners may contribute to the Commons to + promote the ideal of a free culture and the further production of + creative, cultural and scientific works, or to gain reputation or + greater distribution for their Work in part through the use and + efforts of others. + + For these and/or other purposes and motivations, and without any + expectation of additional consideration or compensation, the person + associating CC0 with a Work (the "Affirmer"), to the extent that he or + she is an owner of Copyright and Related Rights in the Work, + voluntarily elects to apply CC0 to the Work and publicly distribute + the Work under its terms, with knowledge of his or her Copyright and + Related Rights in the Work and the meaning and intended legal effect + of CC0 on those rights. + + 1. Copyright and Related Rights. A Work made available under CC0 may + be protected by copyright and related or neighboring rights + ("Copyright and Related Rights"). Copyright and Related Rights + include, but are not limited to, the following: + + the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + moral rights retained by the original author(s) and/or performer(s); + publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + rights protecting the extraction, dissemination, use and reuse of data + in a Work; + database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and + other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations + thereof. + + 2. Waiver. To the greatest extent permitted by, but not in + contravention of, applicable law, Affirmer hereby overtly, fully, + permanently, irrevocably and unconditionally waives, abandons, and + surrenders all of Affirmer's Copyright and Related Rights and + associated claims and causes of action, whether now known or unknown + (including existing as well as future claims and causes of action), in + the Work (i) in all territories worldwide, (ii) for the maximum + duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number + of copies, and (iv) for any purpose whatsoever, including without + limitation commercial, advertising or promotional purposes (the + "Waiver"). Affirmer makes the Waiver for the benefit of each member of + the public at large and to the detriment of Affirmer's heirs and + successors, fully intending that such Waiver shall not be subject to + revocation, rescission, cancellation, termination, or any other legal + or equitable action to disrupt the quiet enjoyment of the Work by the + public as contemplated by Affirmer's express Statement of Purpose. + + 3. Public License Fallback. Should any part of the Waiver for any + reason be judged legally invalid or ineffective under applicable law, + then the Waiver shall be preserved to the maximum extent permitted + taking into account Affirmer's express Statement of Purpose. In + addition, to the extent the Waiver is so judged Affirmer hereby grants + to each affected person a royalty-free, non transferable, non + sublicensable, non exclusive, irrevocable and unconditional license to + exercise Affirmer's Copyright and Related Rights in the Work (i) in + all territories worldwide, (ii) for the maximum duration provided by + applicable law or treaty (including future time extensions), (iii) in + any current or future medium and for any number of copies, and (iv) + for any purpose whatsoever, including without limitation commercial, + advertising or promotional purposes (the "License"). The License shall + be deemed effective as of the date CC0 was applied by Affirmer to the + Work. Should any part of the License for any reason be judged legally + invalid or ineffective under applicable law, such partial invalidity + or ineffectiveness shall not invalidate the remainder of the License, + and in such case Affirmer hereby affirms that he or she will not (i) + exercise any of his or her remaining Copyright and Related Rights in + the Work or (ii) assert any associated claims and causes of action + with respect to the Work, in either case contrary to Affirmer's + express Statement of Purpose. + + 4. Limitations and Disclaimers. + + No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. + + Contributions thanks to: + niXman + Ely Arzhannikov + Alexey Pavlov + Ray Donnelly + Johannes Schindelin + +*/ + +#ifndef PATH_CONV_H_DB4IQBH3 +#define PATH_CONV_H_DB4IQBH3 + +#include + +const char* convert(char *dst, size_t dstlen, const char *src); + +#endif /* end of include guard: PATH_CONV_H_DB4IQBH3 */ + diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 1802e76f71..84851a12f3 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -66,6 +66,7 @@ #include "shared_info.h" #include "tls_pbuf.h" #include "environ.h" +#include "msys2_path_conv.h" #undef basename suffix_info stat_suffixes[] = @@ -3870,6 +3871,74 @@ fchdir (int fd) return res; } +// +// Important: If returned pointer == arg, then this function +// did not malloc that pointer; otherwise free it. +// +extern "C" char * +arg_heuristic_with_exclusions (char const * const arg, char const * exclusions, size_t exclusions_count) +{ + char *arg_result; + + // Must return something .. + size_t arglen = (arg ? strlen (arg): 0); + + if (arglen == 0 || !arg) + { + arg_result = (char *)malloc (sizeof (char)); + arg_result[0] = '\0'; + return arg_result; + } + + debug_printf("Input value: (%s)", arg); + for (size_t excl = 0; excl < exclusions_count; ++excl) + { + /* Since we've got regex linked we should maybe switch to that, but + running regexes for every argument could be too slow. */ + if ( strcmp (exclusions, "*") == 0 || (strlen (exclusions) && strstr (arg, exclusions) == arg) ) + return (char*)arg; + exclusions += strlen (exclusions) + 1; + } + + // Leave enough room for at least 16 path elements; we might be converting + // a path list. + size_t stack_len = arglen + 16 * MAX_PATH; + char * stack_path = (char *)malloc (stack_len); + if (!stack_path) + { + debug_printf ("out of stack space?"); + return (char *)arg; + } + memset (stack_path, 0, MAX_PATH); + convert (stack_path, stack_len - 1, arg); + debug_printf ("convert()'ed: %s (length %d)\n.....->: %s", arg, arglen, stack_path); + // Don't allocate memory if no conversion happened. + if (!strcmp (arg, stack_path)) + { + if (arg != stack_path) + { + free (stack_path); + } + return ((char *)arg); + } + arg_result = (char *)realloc (stack_path, strlen (stack_path)+1); + // Windows doesn't like empty entries in PATH env. variables (;;) + char* semisemi = strstr(arg_result, ";;"); + while (semisemi) + { + memmove(semisemi, semisemi+1, strlen(semisemi)); + semisemi = strstr(semisemi, ";;"); + } + return arg_result; +} + +extern "C" char * +arg_heuristic (char const * const arg) +{ + return arg_heuristic_with_exclusions (arg, NULL, 0); +} + + /******************** Exported Path Routines *********************/ /* Cover functions to the path conversion routines. diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index f5a4b91d76..902cef8ae2 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -292,6 +292,27 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, bool rc; int res = -1; + /* Environment variable MSYS2_ARG_CONV_EXCL contains a list + of ';' separated argument prefixes to pass un-modified.. + It isn't applied to env. variables; only spawn arguments. + A value of * means don't convert any arguments. */ + char* msys2_arg_conv_excl_env = getenv("MSYS2_ARG_CONV_EXCL"); + char* msys2_arg_conv_excl = NULL; + size_t msys2_arg_conv_excl_count = 0; + if (msys2_arg_conv_excl_env) + { + msys2_arg_conv_excl = (char*)alloca (strlen(msys2_arg_conv_excl_env)+1); + strcpy (msys2_arg_conv_excl, msys2_arg_conv_excl_env); + msys2_arg_conv_excl_count = 1; + msys2_arg_conv_excl_env = strchr ( msys2_arg_conv_excl, ';' ); + while (msys2_arg_conv_excl_env) + { + *msys2_arg_conv_excl_env = '\0'; + ++msys2_arg_conv_excl_count; + msys2_arg_conv_excl_env = strchr ( msys2_arg_conv_excl_env + 1, ';' ); + } + } + /* Check if we have been called from exec{lv}p or spawn{lv}p and mask mode to keep only the spawn mode. */ bool p_type_exec = !!(mode & _P_PATH_TYPE_EXEC); @@ -383,6 +404,20 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, moreinfo->argc = newargv.argc; moreinfo->argv = newargv; } + else + { + for (int i = 0; i < newargv.argc; i++) + { + //convert argv to win32 + int newargvlen = strlen (newargv[i]); + char *tmpbuf = (char *)malloc (newargvlen + 1); + memcpy (tmpbuf, newargv[i], newargvlen + 1); + tmpbuf = arg_heuristic_with_exclusions(tmpbuf, msys2_arg_conv_excl, msys2_arg_conv_excl_count); + debug_printf("newargv[%d] = %s", i, newargv[i]); + newargv.replace (i, tmpbuf); + free (tmpbuf); + } + } if ((wincmdln || !real_path.iscygexec ()) && !cmd.fromargv (newargv, real_path.get_win32 (), real_path.iscygexec ())) @@ -513,7 +548,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, moreinfo->envp = build_env (envp, envblock, moreinfo->envc, real_path.iscygexec (), switch_user ? ::cygheap->user.primary_token () - : NULL); + : NULL, + real_path.iscygexec ()); if (!moreinfo->envp || !envblock) { set_errno (E2BIG); From 35a477b5cd63373397b0dc713de7b95d610ad300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 21:29:01 +0300 Subject: [PATCH 060/116] Add functionality for changing OS name via MSYSTEM environment variables. --- winsup/cygserver/cygserver-config | 4 ++-- winsup/cygwin/environ.cc | 34 ++++++++++++++++++++++++++--- winsup/cygwin/include/sys/utsname.h | 2 +- winsup/cygwin/uname.cc | 17 +++++++++++++-- 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/winsup/cygserver/cygserver-config b/winsup/cygserver/cygserver-config index 373bfd24dd..c902857ea7 100755 --- a/winsup/cygserver/cygserver-config +++ b/winsup/cygserver/cygserver-config @@ -86,7 +86,7 @@ done # Check if running on NT _sys="`uname`" -_nt=`expr "${_sys}" : "CYGWIN_NT"` +_nt=`expr "${_sys}" : "MSYS_NT"` # Check for running cygserver processes first. if ps -ef | grep -v grep | grep -q ${service_name} @@ -178,7 +178,7 @@ then echo "Do you want to install cygserver as service?" if request "(Say \"no\" if it's already installed as service)" then - if ! cygrunsrv -I ${service_name} -d "CYGWIN cygserver" -p /usr/sbin/cygserver + if ! cygrunsrv -I ${service_name} -d "MSYS cygserver" -p /usr/sbin/cygserver then echo echo "Installation of cygserver as service failed. Please check the" diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 639e69393b..b9f7e05452 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -192,7 +192,11 @@ parse_options (const char *inbuf) if (export_settings) { debug_printf ("%s", newbuf + 1); +#ifdef __MSYS__ + setenv ("MSYS", newbuf + 1, 1); +#else setenv ("CYGWIN", newbuf + 1, 1); +#endif } return; } @@ -651,7 +655,7 @@ _addenv (const char *name, const char *value, int overwrite) win_env *spenv; if ((spenv = getwinenv (envhere))) spenv->add_cache (value); - if (strcmp (name, "CYGWIN") == 0) + if (strcmp (name, "MSYS") == 0) parse_options (value); return 0; @@ -754,6 +758,9 @@ static struct renv { } renv_arr[] = { { NL("COMMONPROGRAMFILES=") }, // 0 { NL("COMSPEC=") }, +#ifdef __MSYS__ + { NL("MSYSTEM=") }, // 2 +#endif /* __MSYS__ */ { NL("PATH=") }, // 2 { NL("PROGRAMFILES=") }, { NL("SYSTEMDRIVE=") }, // 4 @@ -765,10 +772,21 @@ static struct renv { #define RENV_SIZE (sizeof (renv_arr) / sizeof (renv_arr[0])) /* Set of first characters of the above list of variables. */ -static const char idx_arr[] = "CPSTW"; +static const char idx_arr[] = +#ifdef __MSYS__ + "CMPSTW"; +#else + "CPSTW"; +#endif /* Index into renv_arr at which the variables with this specific character starts. */ -static const int start_at[] = { 0, 2, 4, 6, 8 }; +static const int start_at[] = { +#ifdef __MSYS__ + 0, 2, 3, 5, 7, 9 +#else + 0, 2, 4, 6, 8 +#endif + }; /* Turn environment variable part of a=b string into uppercase - for some environment variables only. */ @@ -836,7 +854,11 @@ environ_init (char **envp, int envc) dumper_init (); if (envp_passed_in) { +#ifdef __MSYS__ + p = getenv ("MSYS"); +#else p = getenv ("CYGWIN"); +#endif if (p) parse_options (p); } @@ -883,8 +905,13 @@ win32env_to_cygenv (PWCHAR rawenv, bool posify) ucenv (newp, eq); /* uppercase env vars which need it */ if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0) sawTERM = 1; +#ifdef __MSYS__ + else if (*newp == 'M' && strncmp (newp, "MSYS=", 5) == 0) + parse_options (newp + 5); +#else else if (*newp == 'C' && strncmp (newp, "CYGWIN=", 7) == 0) parse_options (newp + 7); +#endif if (*eq && posify) posify_maybe (envp + i, *++eq ? eq : --eq, tmpbuf); debug_printf ("%p: %s", envp[i], envp[i]); @@ -959,6 +986,7 @@ static NO_COPY spenv spenvs[] = {NL ("HOMEPATH="), false, false, &cygheap_user::env_homepath}, {NL ("LOGONSERVER="), false, false, &cygheap_user::env_logsrv}, {NL ("PATH="), false, true, NULL}, + {NL ("MSYSTEM="), true, true, NULL}, {NL ("SYSTEMDRIVE="), false, true, NULL}, {NL ("SYSTEMROOT="), true, true, &cygheap_user::env_systemroot}, {NL ("USERDOMAIN="), false, false, &cygheap_user::env_domain}, diff --git a/winsup/cygwin/include/sys/utsname.h b/winsup/cygwin/include/sys/utsname.h index d6b3be96f7..730cb731a5 100644 --- a/winsup/cygwin/include/sys/utsname.h +++ b/winsup/cygwin/include/sys/utsname.h @@ -17,7 +17,7 @@ extern "C" { struct utsname { - char sysname[_UTSNAME_LENGTH]; + char sysname[_UTSNAME_LENGTH + 1]; char nodename[_UTSNAME_LENGTH]; char release[_UTSNAME_LENGTH]; char version[_UTSNAME_LENGTH]; diff --git a/winsup/cygwin/uname.cc b/winsup/cygwin/uname.cc index dd4160189c..0d0c5aa52a 100644 --- a/winsup/cygwin/uname.cc +++ b/winsup/cygwin/uname.cc @@ -36,7 +36,12 @@ uname_x (struct utsname *name) memset (name, 0, sizeof (*name)); /* sysname */ - __small_sprintf (name->sysname, "CYGWIN_%s-%u", + char* msystem = getenv("MSYSTEM"); + const char* msystem_sysname = "MSYS"; + if (msystem != NULL && *msystem && strcmp(msystem, "MSYS") != 0) + msystem_sysname = (strstr(msystem, "32") != NULL) ? "MINGW32" : "MINGW64";; + __small_sprintf (name->sysname, "%s_%s-%u", + msystem_sysname, wincap.osname (), wincap.build_number ()); /* nodename */ memset (buf, 0, sizeof buf); @@ -88,7 +93,7 @@ uname_x (struct utsname *name) /* Old entrypoint for applications up to API 334 */ struct old_utsname { - char sysname[20]; + char sysname[21]; char nodename[20]; char release[20]; char version[20]; @@ -102,7 +107,15 @@ uname (struct utsname *in_name) __try { memset (name, 0, sizeof (*name)); +#ifdef __MSYS__ + char* msystem = getenv("MSYSTEM"); + const char* msystem_sysname = "MSYS"; + if (msystem != NULL && *msystem && strcmp(msystem, "MSYS") != 0) + msystem_sysname = (strstr(msystem, "32") != NULL) ? "MINGW32" : "MINGW64"; + __small_sprintf (name->sysname, "%s_%s", msystem_sysname, wincap.osname ()); +#else __small_sprintf (name->sysname, "CYGWIN_%s", wincap.osname ()); +#endif /* Computer name */ cygwin_gethostname (name->nodename, sizeof (name->nodename) - 1); From 41ed62e6f51e80b764de465ab9f9045552107813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 21:45:06 +0300 Subject: [PATCH 061/116] - Move root to /usr. - Change sorting mount points. - By default mount without ACLs. - Can read /etc/fstab with short mount point format. --- winsup/cygwin/local_includes/mount.h | 3 +- winsup/cygwin/mm/cygheap.cc | 12 +- winsup/cygwin/mount.cc | 185 +++++++++++++++++++++++---- winsup/cygwin/uinfo.cc | 2 +- 4 files changed, 174 insertions(+), 28 deletions(-) diff --git a/winsup/cygwin/local_includes/mount.h b/winsup/cygwin/local_includes/mount.h index b2acdf08b4..1fc5c39b76 100644 --- a/winsup/cygwin/local_includes/mount.h +++ b/winsup/cygwin/local_includes/mount.h @@ -172,7 +172,6 @@ class mount_info mount_item mount[MAX_MOUNTS]; static bool got_usr_bin; - static bool got_usr_lib; static int root_idx; /* cygdrive_prefix is used as the root of the path automatically @@ -184,6 +183,8 @@ class mount_info private: int posix_sorted[MAX_MOUNTS]; int native_sorted[MAX_MOUNTS]; + int longest_posix_sorted[MAX_MOUNTS]; + int shortest_native_sorted[MAX_MOUNTS]; public: void init (bool); diff --git a/winsup/cygwin/mm/cygheap.cc b/winsup/cygwin/mm/cygheap.cc index 3dc0c011fa..bf4d82f07c 100644 --- a/winsup/cygwin/mm/cygheap.cc +++ b/winsup/cygwin/mm/cygheap.cc @@ -220,14 +220,22 @@ init_cygheap::init_installation_root () /* Strip off last path component ("\\cygwin1.dll") */ PWCHAR w = wcsrchr (installation_root_buf, L'\\'); +#ifdef __MSYS__ + /* Back two folders to get root as we have all stuff in usr subfolder */ + for (int i=1; i >=0; --i) + { +#endif if (w) { *w = L'\0'; w = wcsrchr (installation_root_buf, L'\\'); } if (!w) - api_fatal ("Can't initialize Cygwin installation root dir.\n" + api_fatal ("Can't initialize MSYS2 installation root dir.\n" "Invalid DLL path"); +#ifdef __MSYS__ + } +#endif /* Copy result into installation_dir before stripping off "bin" dir and revert to Win32 path. This path is added to the Windows environment @@ -252,6 +260,7 @@ init_cygheap::init_installation_root () RtlInitUnicodeString (&installation_root, installation_root_buf); RtlInitUnicodeString (&installation_dir, installation_dir_buf); +#ifndef __MSYS__ for (int i = 1; i >= 0; --i) { reg_key r (i, KEY_WRITE, _WIDE (CYGWIN_INFO_INSTALLATIONS_NAME), @@ -260,6 +269,7 @@ init_cygheap::init_installation_root () installation_root_buf))) break; } +#endif } /* Initialize bucket_val. The value is the max size of a block diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc index bf26c4af3e..eff9803241 100644 --- a/winsup/cygwin/mount.cc +++ b/winsup/cygwin/mount.cc @@ -42,7 +42,6 @@ details. */ (path_prefix_p (proc, (path), proc_len, false)) bool NO_COPY mount_info::got_usr_bin; -bool NO_COPY mount_info::got_usr_lib; int NO_COPY mount_info::root_idx = -1; /* is_native_path: Return non-zero if PATH starts with \??\[a-zA-Z] or @@ -395,7 +394,6 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol) #define MINIMAL_WIN_NTFS_FLAGS (FILE_CASE_SENSITIVE_SEARCH \ | FILE_CASE_PRESERVED_NAMES \ | FILE_UNICODE_ON_DISK \ - | FILE_PERSISTENT_ACLS \ | FILE_FILE_COMPRESSION \ | FILE_VOLUME_QUOTAS \ | FILE_SUPPORTS_SPARSE_FILES \ @@ -552,13 +550,13 @@ mount_info::create_root_entry (const PWCHAR root) sys_wcstombs (native_root, PATH_MAX, root); assert (*native_root != '\0'); if (add_item (native_root, "/", - MOUNT_SYSTEM | MOUNT_IMMUTABLE | MOUNT_AUTOMATIC) + MOUNT_SYSTEM | MOUNT_IMMUTABLE | MOUNT_AUTOMATIC | MOUNT_NOACL) < 0) api_fatal ("add_item (\"%s\", \"/\", ...) failed, errno %d", native_root, errno); /* Create a default cygdrive entry. Note that this is a user entry. This allows to override it with mount, unless the sysadmin created a cygdrive entry in /etc/fstab. */ - cygdrive_flags = MOUNT_NOPOSIX | MOUNT_CYGDRIVE; + cygdrive_flags = MOUNT_NOPOSIX | MOUNT_CYGDRIVE | MOUNT_NOACL; strcpy (cygdrive, CYGWIN_INFO_CYGDRIVE_DEFAULT_PREFIX "/"); cygdrive_len = strlen (cygdrive); } @@ -578,22 +576,14 @@ mount_info::init (bool user_init) pathend = wcpcpy (pathend, L"\\etc\\fstab"); from_fstab (user_init, path, pathend); - if (!user_init && (!got_usr_bin || !got_usr_lib)) + if (!user_init && !got_usr_bin) { char native[PATH_MAX]; if (root_idx < 0) - api_fatal ("root_idx %d, user_shared magic %y, nmounts %d", root_idx, user_shared->version, nmounts); + api_fatal ("root_idx %d, user_shared magic %y, nmounts %d", root_idx, user_shared->version, nmounts); char *p = stpcpy (native, mount[root_idx].native_path); - if (!got_usr_bin) - { - stpcpy (p, "\\bin"); - add_item (native, "/usr/bin", MOUNT_SYSTEM | MOUNT_AUTOMATIC); - } - if (!got_usr_lib) - { - stpcpy (p, "\\lib"); - add_item (native, "/usr/lib", MOUNT_SYSTEM | MOUNT_AUTOMATIC); - } + stpcpy (p, "\\usr\\bin"); + add_item (native, "/bin", MOUNT_SYSTEM | MOUNT_AUTOMATIC | MOUNT_NOACL); } } @@ -674,6 +664,7 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, /* See if this is a cygwin "device" */ if (win32_device_name (src_path, dst, dev)) { + debug_printf ("win32_device_name (%s)", src_path); *flags = 0; rc = 0; goto out_no_chroot_check; @@ -711,6 +702,7 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, } if (isproc (src_path)) { + debug_printf ("isproc (%s)", src_path); dev = *proc_dev; dev = fhandler_proc::get_proc_fhandler (src_path); if (dev == FH_NADA) @@ -732,6 +724,7 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, off the prefix and transform it into an MS-DOS path. */ else if (iscygdrive (src_path)) { + debug_printf ("iscygdrive (%s) mount_table->cygdrive %s", src_path, mount_table->cygdrive); int n = mount_table->cygdrive_len - 1; int unit; @@ -743,11 +736,15 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, } else if (cygdrive_win32_path (src_path, dst, unit)) { + debug_printf ("cygdrive_win32_path (%s)", src_path); *flags = cygdrive_flags; goto out; } else if (mount_table->cygdrive_len > 1) - return ENOENT; + { + debug_printf ("mount_table->cygdrive_len > 1 (%s)", src_path); + return ENOENT; + } } int chroot_pathlen; @@ -758,7 +755,9 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, const char *path; int len; - mi = mount + posix_sorted[i]; + mi = mount + shortest_native_sorted[i]; + debug_printf (" mount[%d] .. checking %s -> %s ", i, mi->posix_path, mi->native_path); + if (!cygheap->root.exists () || (mi->posix_pathlen == 1 && mi->posix_path[0] == '/')) { @@ -998,7 +997,8 @@ mount_info::conv_to_posix_path (const char *src_path, char *posix_path, int pathbuflen = tail - pathbuf; for (int i = 0; i < nmounts; ++i) { - mount_item &mi = mount[native_sorted[i]]; + mount_item &mi = mount[longest_posix_sorted[i]]; + debug_printf (" mount[%d] .. checking %s -> %s ", i, mi.posix_path, mi.native_path); if (!path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen, mi.flags & MOUNT_NOPOSIX)) continue; @@ -1211,8 +1211,17 @@ mount_info::from_fstab_line (char *line, bool user) if (!*c) return true; cend = find_ws (c); - *cend = '\0'; posix_path = conv_fstab_spaces (c); + if (!*cend) + { + unsigned mount_flags = MOUNT_SYSTEM | MOUNT_NOPOSIX | MOUNT_NOACL; + + int res = mount_table->add_item (native_path, posix_path, mount_flags); + if (res && get_errno () == EMFILE) + return false; + return true; + } + *cend = '\0'; /* Third field: FS type. */ c = skip_ws (cend + 1); if (!*c) @@ -1441,16 +1450,145 @@ sort_by_native_name (const void *a, const void *b) return res; } +/* sort_by_longest_posix_name: qsort callback to sort the mount entries. + Sort user mounts ahead of system mounts to the same POSIX path. */ +/* FIXME: should the user should be able to choose whether to + prefer user or system mounts??? */ +static int +sort_by_longest_posix_name (const void *a, const void *b) +{ + mount_item *ap = mounts_for_sort + (*((int*) a)); + mount_item *bp = mounts_for_sort + (*((int*) b)); + + /* Base weighting on the conversion that would give the longest + posix path. */ + ssize_t alen = (ssize_t) strlen (ap->posix_path) - (ssize_t) strlen (ap->native_path); + ssize_t blen = (ssize_t) strlen (bp->posix_path) - (ssize_t) strlen (bp->native_path); + + int res = blen - alen; + + if (res) + return res; /* Path lengths differed */ + + /* The two paths were the same length, so just determine normal + lexical sorted order. */ + res = strcmp (ap->posix_path, bp->posix_path); + + if (res == 0) + { + /* need to select between user and system mount to same POSIX path */ + if (!(bp->flags & MOUNT_SYSTEM)) /* user mount */ + return 1; + else + return -1; + } + + return res; +} + +/* sort_by_shortest_native_name: qsort callback to sort the mount entries. + Sort user mounts ahead of system mounts to the same POSIX path. */ +/* FIXME: should the user should be able to choose whether to + prefer user or system mounts??? */ +static int +sort_by_shortest_native_name (const void *a, const void *b) +{ + mount_item *ap = mounts_for_sort + (*((int*) a)); + mount_item *bp = mounts_for_sort + (*((int*) b)); + + /* Base weighting on the conversion that would give the shortest + native path. */ + ssize_t alen = (ssize_t) strlen (ap->native_path); + ssize_t blen = (ssize_t) strlen (bp->native_path); + + int res = alen - blen; + + if (res) + return res; /* Path lengths differed */ + + /* The two paths were the same length, so just determine normal + lexical sorted order. */ + res = strcmp (ap->native_path, bp->native_path); + + if (res == 0) + { + /* need to select between user and system mount to same POSIX path */ + if (!(bp->flags & MOUNT_SYSTEM)) /* user mount */ + return 1; + else + return -1; + } + + return res; +} + +static int +sort_posix_subdirs_before_parents (const void *a, const void *b) +{ + mount_item *ap = mounts_for_sort + (*((int*) a)); + mount_item *bp = mounts_for_sort + (*((int*) b)); + + if (ap->posix_pathlen > bp->posix_pathlen) + { + if (!memcmp (bp->posix_path, ap->posix_path, bp->posix_pathlen)) + { + // bp is a subdir of ap (bp must be moved in-front) + return -1; + } + } + else if (ap->posix_pathlen < bp->posix_pathlen) + { + if (!memcmp (ap->posix_path, bp->posix_path, ap->posix_pathlen)) + { + // ap is a subdir of bp (good as we are) + return 1; + } + } + return 0; +} + +#define DISABLE_NEW_STUFF 0 +#define ONLY_USE_NEW_STUFF 1 + void mount_info::sort () { for (int i = 0; i < nmounts; i++) - native_sorted[i] = posix_sorted[i] = i; + native_sorted[i] = posix_sorted[i] = shortest_native_sorted[i] = longest_posix_sorted[i] = i; /* Sort them into reverse length order, otherwise we won't be able to look for /foo in /. */ mounts_for_sort = mount; /* ouch. */ qsort (posix_sorted, nmounts, sizeof (posix_sorted[0]), sort_by_posix_name); qsort (native_sorted, nmounts, sizeof (native_sorted[0]), sort_by_native_name); + qsort (longest_posix_sorted, nmounts, sizeof (longest_posix_sorted[0]), sort_by_longest_posix_name); + qsort (shortest_native_sorted, nmounts, sizeof (shortest_native_sorted[0]), sort_by_shortest_native_name); + qsort (shortest_native_sorted, nmounts, sizeof (shortest_native_sorted[0]), sort_posix_subdirs_before_parents); + /* Disabling my new crap. */ + #if DISABLE_NEW_STUFF + for (int i = 0; i < nmounts; i++) + { + longest_posix_sorted[i] = native_sorted[i]; + shortest_native_sorted[i] = posix_sorted[i]; + } + #else + #if ONLY_USE_NEW_STUFF + for (int i = 0; i < nmounts; i++) + { + native_sorted[i] = longest_posix_sorted[i]; + posix_sorted[i] = shortest_native_sorted[i]; + } + #endif + #endif + for (int i = 0; i < nmounts; i++) + { + mount_item *mi = mount + shortest_native_sorted[i]; + debug_printf ("shortest_native_sorted (subdirs before parents)[%d] %12s %12s", i, mi->native_path, mi->posix_path); + } + for (int i = 0; i < nmounts; i++) + { + mount_item *mi = mount + longest_posix_sorted[i]; + debug_printf ("longest_posix_sorted[%d] %12s %12s", i, mi->native_path, mi->posix_path); + } } /* Add an entry to the mount table. @@ -1541,12 +1679,9 @@ mount_info::add_item (const char *native, const char *posix, if (i == nmounts) nmounts++; - if (strcmp (posixtmp, "/usr/bin") == 0) + if (strcmp (posixtmp, "/bin") == 0) got_usr_bin = true; - if (strcmp (posixtmp, "/usr/lib") == 0) - got_usr_lib = true; - if (posixtmp[0] == '/' && posixtmp[1] == '\0' && !(mountflags & MOUNT_CYGDRIVE)) root_idx = i; diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index acbc945e41..81d9529824 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -2827,7 +2827,7 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap) dom, name, sid.string ((char *) sidstr), home ?: "/home/", home ? L"" : name, - shell ?: "/bin/bash"); + shell ?: "/usr/bin/bash"); if (gecos) free (gecos); if (home) From 8096583fac66461dbe1414f210d998a3087c1ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 21:47:21 +0300 Subject: [PATCH 062/116] Instead of creating Cygwin symlinks, use deep copy by default The new `winsymlinks` mode `deepcopy` (which is made the default) lets calls to `symlink()` create (deep) copies of the source file/directory. This is necessary because unlike Cygwin, MSYS2 does not try to be its own little ecosystem that lives its life separate from regular Win32 programs: the latter have _no idea_ about Cygwin-emulated symbolic links (i.e. system files whose contents start with `!\xff\xfe` and the remainder consists of the NUL-terminated, UTF-16LE-encoded symlink target). To support Cygwin-style symlinks, the new mode `sysfile` is introduced. Co-authored-by: Johannes Schindelin --- winsup/cygwin/environ.cc | 4 + winsup/cygwin/globals.cc | 3 +- winsup/cygwin/path.cc | 154 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index b9f7e05452..5fb3f53ef5 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -88,6 +88,10 @@ set_winsymlinks (const char *buf) else if (ascii_strncasematch (buf, "native", 6)) allow_winsymlinks = ascii_strcasematch (buf + 6, "strict") ? WSYM_nativestrict : WSYM_native; + else if (ascii_strncasematch (buf, "deepcopy", 8)) + allow_winsymlinks = WSYM_deepcopy; + else + allow_winsymlinks = WSYM_sysfile; } /* The structure below is used to set up an array which is used to diff --git a/winsup/cygwin/globals.cc b/winsup/cygwin/globals.cc index d14ea593f6..0c21fa624e 100644 --- a/winsup/cygwin/globals.cc +++ b/winsup/cygwin/globals.cc @@ -57,6 +57,7 @@ enum winsym_t WSYM_nativestrict, WSYM_nfs, WSYM_sysfile, + WSYM_deepcopy }; exit_states NO_COPY exit_state; @@ -70,7 +71,7 @@ bool ignore_case_with_glob; bool pipe_byte = true; /* Default to byte mode so that C# programs work. */ bool reset_com; bool wincmdln; -winsym_t allow_winsymlinks = WSYM_default; +winsym_t allow_winsymlinks = WSYM_deepcopy; bool disable_pcon; bool winjitdebug = false; diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 84851a12f3..8615386aff 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -1682,6 +1682,89 @@ conv_path_list (const char *src, char *dst, size_t size, /********************** Symbolic Link Support **************************/ +/* + Create a deep copy of src as dst, while avoiding descending in origpath. +*/ +static int +recursiveCopy (char * src, char * dst, const char * origpath) +{ + WIN32_FIND_DATA dHfile; + HANDLE dH = INVALID_HANDLE_VALUE; + BOOL findfiles; + int srcpos = strlen (src); + int dstpos = strlen (dst); + int res = -1; + + debug_printf("recursiveCopy (%s, %s)", src, dst); + + /* Create the destination directory */ + if (!CreateDirectoryEx (src, dst, NULL)) + { + debug_printf("CreateDirectoryEx(%s, %s, 0) failed", src, dst); + __seterrno (); + goto done; + } + /* Descend into the source directory */ + if (srcpos + 2 >= MAX_PATH || dstpos + 1 >= MAX_PATH) + { + set_errno (ENAMETOOLONG); + goto done; + } + strcat (src, "\\*"); + strcat (dst, "\\"); + dH = FindFirstFile (src, &dHfile); + debug_printf("dHfile(1): %s", dHfile.cFileName); + findfiles = FindNextFile (dH, &dHfile); + debug_printf("dHfile(2): %s", dHfile.cFileName); + findfiles = FindNextFile (dH, &dHfile); + while (findfiles) + { + /* Append the directory item filename to both source and destination */ + int filelen = strlen (dHfile.cFileName); + debug_printf("dHfile(3): %s", dHfile.cFileName); + if (srcpos + 1 + filelen >= MAX_PATH || + dstpos + 1 + filelen >= MAX_PATH) + { + set_errno (ENAMETOOLONG); + goto done; + } + strcpy (&src[srcpos+1], dHfile.cFileName); + strcpy (&dst[dstpos+1], dHfile.cFileName); + debug_printf("%s -> %s", src, dst); + if (dHfile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + /* Recurse into the child directory */ + debug_printf("%s <-> %s", src, origpath); + if (strcmp (src, origpath)) // avoids endless recursion + if (recursiveCopy (src, dst, origpath)) + goto done; + } + else + { + /* Just copy the file */ + if (!CopyFile (src, dst, FALSE)) + { + __seterrno (); + goto done; + } + } + findfiles = FindNextFile (dH, &dHfile); + } + if (GetLastError() != ERROR_NO_MORE_FILES) + { + __seterrno (); + goto done; + } + res = 0; + +done: + + if (dH != INVALID_HANDLE_VALUE) + FindClose (dH); + + return res; +} + /* Create a symlink from FROMPATH to TOPATH. */ extern "C" int @@ -2219,6 +2302,77 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice) } else /* wsym_type == WSYM_sysfile */ { + if (wsym_type == WSYM_deepcopy) + { + path_conv src_path; + src_path.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes); + if (src_path.error) + { + set_errno (src_path.error); + __leave; + } + if (!src_path.isdevice () && !src_path.is_fs_special ()) + { + /* MSYS copy file instead make symlink */ + + char * real_oldpath; + if (isabspath (oldpath)) + strcpy (real_oldpath = tp.c_get (), oldpath); + else + /* Find the real source path, relative + to the directory of the destination */ + { + /* Determine the character position of the last path component */ + const char *newpath = win32_newpath.get_posix(); + int pos = strlen (newpath); + while (--pos >= 0) + if (isdirsep (newpath[pos])) + break; + /* Append the source path to the directory + component of the destination */ + if (pos+1+strlen(oldpath) >= MAX_PATH) + { + set_errno(ENAMETOOLONG); + __leave; + } + strcpy (real_oldpath = tp.c_get (), newpath); + strcpy (&real_oldpath[pos+1], oldpath); + } + + /* As a MSYS limitation, the source path must exist. */ + path_conv win32_oldpath; + win32_oldpath.check (real_oldpath, PC_SYM_NOFOLLOW, stat_suffixes); + if (!win32_oldpath.exists ()) + { + set_errno (ENOENT); + __leave; + } + + char *w_newpath; + char *w_oldpath; + stpcpy (w_newpath = tp.c_get (), win32_newpath.get_win32()); + stpcpy (w_oldpath = tp.c_get (), win32_oldpath.get_win32()); + if (win32_oldpath.isdir()) + { + char *origpath; + strcpy (origpath = tp.c_get (), w_oldpath); + res = recursiveCopy (w_oldpath, w_newpath, origpath); + } + else + { + if (!CopyFile (w_oldpath, w_newpath, FALSE)) + { + __seterrno (); + } + else + { + res = 0; + } + } + __leave; + } + } + /* Default technique creating a symlink. */ buf = tp.t_get (); cp = stpcpy (buf, SYMLINK_COOKIE); From 0ba54e8cc1940f94e9cde6b6c74cb6a8fb240d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 21:48:54 +0300 Subject: [PATCH 063/116] Automatically rewrite TERM=msys to TERM=cygwin With MSys1, it was necessary to set the TERM variable to "msys". To allow for a smooth transition from MSys1 to MSys2, let's simply handle TERM=msys as if the user had not specified TERM at all and wanted us to use our preferred TERM value. --- winsup/cygwin/environ.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 5fb3f53ef5..117531367e 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -908,7 +908,16 @@ win32env_to_cygenv (PWCHAR rawenv, bool posify) char *eq = strchrnul (newp, '='); ucenv (newp, eq); /* uppercase env vars which need it */ if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0) - sawTERM = 1; + { + /* backwards compatibility: override TERM=msys by TERM=cygwin */ + if (strcmp (newp + 5, "msys") == 0) + { + free(newp); + i--; + continue; + } + sawTERM = 1; + } #ifdef __MSYS__ else if (*newp == 'M' && strncmp (newp, "MSYS=", 5) == 0) parse_options (newp + 5); From e28b7422e206f39202a9f1f840a84cd7a59287c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 21:50:55 +0300 Subject: [PATCH 064/116] Do not convert environment for strace Strace is a Windows program so MSYS2 will convert all arguments and environment vars and that makes debugging msys2 software with strace very tricky. --- winsup/cygwin/spawn.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index 902cef8ae2..d7affaac88 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -545,11 +545,13 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, bool switch_user = ::cygheap->user.issetuid () && (::cygheap->user.saved_uid != ::cygheap->user.real_uid); + bool keep_posix = (iscmd (argv[0], "strace.exe") + || iscmd (argv[0], "strace")) ? true : real_path.iscygexec (); moreinfo->envp = build_env (envp, envblock, moreinfo->envc, real_path.iscygexec (), switch_user ? ::cygheap->user.primary_token () : NULL, - real_path.iscygexec ()); + keep_posix); if (!moreinfo->envp || !envblock) { set_errno (E2BIG); From 4a24304b8b1463097d2532f327eb9e44f272a303 Mon Sep 17 00:00:00 2001 From: Ray Donnelly Date: Sun, 23 Aug 2015 20:47:30 +0100 Subject: [PATCH 065/116] strace.cc: Don't set MSYS=noglob Commit message for this code was: * strace.cc (create_child): Set CYGWIN=noglob when starting new process so that Cygwin will leave already-parsed the command line alonw." I can see no reason for it and it badly breaks the ability to use strace.exe to investigate calling a Cygwin program from a Windows program, for example: strace mingw32-make.exe .. where mingw32-make.exe finds sh.exe and uses it as the shell. The reason it badly breaks this use-case is because dcrt0.cc depends on globbing to happen to parse commandlines from Windows programs; irrespective of whether they contain any glob patterns or not. See quoted () comment: "This must have been run from a Windows shell, so preserve quotes for globify to play with later." --- winsup/utils/mingw/strace.cc | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/winsup/utils/mingw/strace.cc b/winsup/utils/mingw/strace.cc index 29db640239..25adf4e8dd 100644 --- a/winsup/utils/mingw/strace.cc +++ b/winsup/utils/mingw/strace.cc @@ -354,10 +354,28 @@ create_child (char **argv) make_command_line (one_line, argv); SetConsoleCtrlHandler (NULL, 0); +/* Commit message for this code was: +"* strace.cc (create_child): Set CYGWIN=noglob when starting new process so that + + Cygwin will leave already-parsed the command line alonw." + + I can see no reason for it and it badly breaks the ability to use + strace.exe to investigate calling a Cygwin program from a Windows + program, for example: + strace mingw32-make.exe + .. where mingw32-make.exe finds sh.exe and uses it as the shell. + The reason it badly breaks this use-case is because dcrt0.cc depends + on globbing to happen to parse commandlines from Windows programs; + irrespective of whether they contain any glob patterns or not. + + See quoted () comment: + "This must have been run from a Windows shell, so preserve + quotes for globify to play with later." + const char *cygwin_env = getenv ("MSYS"); const char *space; - if (cygwin_env && strlen (cygwin_env) <= 256) /* sanity check */ + if (cygwin_env && strlen (cygwin_env) <= 256) // sanity check space = " "; else space = cygwin_env = ""; @@ -365,6 +383,7 @@ create_child (char **argv) + strlen (space) + strlen (cygwin_env)); sprintf (newenv, "MSYS=noglob%s%s", space, cygwin_env); _putenv (newenv); +*/ ret = CreateProcess (0, one_line.buf, /* command line */ NULL, /* Security */ NULL, /* thread */ From b3a4a5bd44740716566e221dba0625e117d92ab4 Mon Sep 17 00:00:00 2001 From: Ray Donnelly Date: Fri, 21 Aug 2015 09:52:47 +0100 Subject: [PATCH 066/116] Add debugging for strace make_command_line --- winsup/utils/mingw/strace.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/winsup/utils/mingw/strace.cc b/winsup/utils/mingw/strace.cc index 25adf4e8dd..d346abc4e7 100644 --- a/winsup/utils/mingw/strace.cc +++ b/winsup/utils/mingw/strace.cc @@ -352,6 +352,7 @@ create_child (char **argv) flags |= CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP; make_command_line (one_line, argv); + printf ("create_child: %s\n", one_line.buf); SetConsoleCtrlHandler (NULL, 0); /* Commit message for this code was: From f8c098028cde692958bfed365c8877a038860d6c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 17 May 2017 18:13:32 +0200 Subject: [PATCH 067/116] strace --quiet: be *really* quiet The biggest problem with strace spitting out `create_child: ...` despite being asked to be real quiet is that its output can very well interfere with scripts' operations. For example, when running any of Git for Windows' shell scripts with `GIT_STRACE_COMMANDS=/path/to/logfile` (which is sadly an often needed debugging technique while trying to address the many MSYS2 issues Git for Windows faces), any time the output of any command is redirected into a variable, it will include that `create_child: ...` line, wreaking havoc with Git's expectations. So let's just really be quiet when we're asked to be quiet. Signed-off-by: Johannes Schindelin --- winsup/utils/mingw/strace.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/winsup/utils/mingw/strace.cc b/winsup/utils/mingw/strace.cc index d346abc4e7..a6b2e5d548 100644 --- a/winsup/utils/mingw/strace.cc +++ b/winsup/utils/mingw/strace.cc @@ -352,7 +352,8 @@ create_child (char **argv) flags |= CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP; make_command_line (one_line, argv); - printf ("create_child: %s\n", one_line.buf); + if (!quiet) + printf ("create_child: %s\n", one_line.buf); SetConsoleCtrlHandler (NULL, 0); /* Commit message for this code was: From c4d9d83ede9abf0c47949bd3ac6f91fd3325dc64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 22:13:51 +0300 Subject: [PATCH 068/116] path_conv: special-case root directory to have trailing slash When converting `/c/` to `C:\`, the trailing slash is actually really necessary, as `C:` is not an absolute path. We must be very careful to do this only for root directories, though. If we kept the trailing slash also for, say, `/y/directory/`, we would run into the following issue: On FAT file systems, the normalized path is used to fake inode numbers. As a result, `Y:\directory\` and `Y:\directory` have different inode numbers!!! This would result in very non-obvious symptoms. Back when we were too careless about keeping the trailing slash, it was reported to the Git for Windows project that the `find` and `rm` commands can error out on FAT file systems with very confusing "No such file or directory" errors, for no good reason. During the original investigation, Vasil Minkov pointed out in https://github.com/git-for-windows/git/issues/1497#issuecomment-372665870, that this bug had been fixed in Cygwin as early as 1997... and the bug was unfortunately reintroduced into early MSYS2 versions. Signed-off-by: Johannes Schindelin --- winsup/cygwin/path.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 8615386aff..b1a088a9fd 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -709,6 +709,12 @@ path_conv::check (const char *src, unsigned opt, need_directory = 1; *--tail = '\0'; } + /* Special case for "/" must set need_directory, without removing + trailing slash */ + else if (tail == path_copy + 1 && isslash (tail[-1])) + { + need_directory = 1; + } path_end = tail; /* Scan path_copy from right to left looking either for a symlink @@ -1248,6 +1254,7 @@ path_conv::check (const char *src, unsigned opt, cfree (wide_path); wide_path = NULL; } + if (need_directory) { size_t n = strlen (this->path); From 1c5a6e869c61b66c9924c38a9948413667e3ee44 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 8 Nov 2022 16:24:20 +0100 Subject: [PATCH 069/116] When converting to a Unix path, avoid double trailing slashes When calling `cygpath -u C:/msys64/` in an MSYS2 setup that was installed into `C:/msys64/`, the result should be `/`, not `//`. Let's ensure that we do not append another trailing slash if the converted path already ends in a slash. This fixes https://github.com/msys2/msys2-runtime/issues/112 Signed-off-by: Johannes Schindelin --- winsup/cygwin/mount.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc index eff9803241..bd6ec2a7a1 100644 --- a/winsup/cygwin/mount.cc +++ b/winsup/cygwin/mount.cc @@ -1018,6 +1018,9 @@ mount_info::conv_to_posix_path (const char *src_path, char *posix_path, nextchar = 1; int addslash = nextchar > 0 ? 1 : 0; + /* avoid appending a slash if the result already has a trailing slash */ + if (append_slash && mi.posix_pathlen && mi.posix_path[mi.posix_pathlen-1] == '/') + append_slash = addslash = 0; if ((mi.posix_pathlen + (pathbuflen - mi.native_pathlen) + addslash) >= NT_MAX_PATH) return ENAMETOOLONG; strcpy (posix_path, mi.posix_path); From 8b5e9b55a1021d73b91a49cc640f2817394a5bb5 Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Sun, 20 Nov 2022 13:57:36 +0100 Subject: [PATCH 070/116] msys2_path_conv: pass PC_NOFULL to path_conv In theory this doesn't make a difference because posix_to_win32_path() is only called with rooted/absolute paths, but as pointed out in https://github.com/msys2/msys2-runtime/pull/103 PC_NOFULL will preserve the trailing slash of unix paths (for some reason). See "cygpath -m /bin/" (preserved) vs "cygpath -am /bin/" (dropped) One use case where we need to trailing slashes to be preserved is the GCC build system: https://github.com/gcc-mirror/gcc/blob/6d82e0fea5f988e829912a/gcc/Makefile.in#L2314 The Makefile appends a slash to the prefixes and the C code doing relocation will treat the path as a directory if there is a trailing slash. See https://github.com/msys2/MINGW-packages/issues/14173 for details. With this change all our MSYS2 path_conv tests pass again. --- winsup/cygwin/msys2_path_conv.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/msys2_path_conv.cc b/winsup/cygwin/msys2_path_conv.cc index c52728759e..d584800c00 100644 --- a/winsup/cygwin/msys2_path_conv.cc +++ b/winsup/cygwin/msys2_path_conv.cc @@ -682,7 +682,7 @@ void posix_to_win32_path(const char* from, const char* to, char** dst, const cha strncpy(one_path, from, to-from); one_path[to-from] = '\0'; - path_conv conv (one_path, 0); + path_conv conv (one_path, PC_NOFULL); if (conv.error) { set_errno(conv.error); From b09fb7fd5a22f32b58938da80aff0d02193c64c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A7=88=EB=88=84=EC=97=98?= Date: Wed, 17 Jun 2015 09:30:41 +0200 Subject: [PATCH 071/116] path-conversion: Introduce ability to switch off conversion. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When calling windows native apps from MSYS2, the runtime tries to convert commandline arguments by a specific set of rules. This idea was inherited from the MSys/MinGW project (which is now seemingly stale, yet must be credited with championing this useful feature, see MinGW wiki https://web.archive.org/web/20201112005258/http://www.mingw.org/wiki/Posix_path_conversion). If the user does not want that behavior on a big scale, e.g. inside a Bash script, with the changes introduced in this commit, the user can now set the the environment variable `MSYS_NO_PATHCONV` when calling native windows commands. This is a feature that has been introduced in Git for Windows via https://github.com/git-for-windows/msys2-runtime/pull/11 and it predates support for the `MSYS2_ENV_CONV_EXCL` and `MSYS2_ARG_CONV_EXCL` environment variables in the MSYS2 runtime; Many users find the simplicity of `MSYS_NO_PATHCONV` appealing. So let's teach MSYS2 proper this simple trick that still allows using the sophisticated `MSYS2_*_CONV_EXCL` facilities but also offers a convenient catch-all "just don't convert anything" knob. Signed-off-by: 마누엘 Signed-off-by: Johannes Schindelin --- winsup/cygwin/msys2_path_conv.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/winsup/cygwin/msys2_path_conv.cc b/winsup/cygwin/msys2_path_conv.cc index d584800c00..4c0cc82cf2 100644 --- a/winsup/cygwin/msys2_path_conv.cc +++ b/winsup/cygwin/msys2_path_conv.cc @@ -341,6 +341,16 @@ path_type find_path_start_and_type(const char** src, int recurse, const char* en if (*it == '\0' || it == end) return NONE; + /* + * Skip path mangling when environment indicates it. + */ + const char *no_pathconv = getenv ("MSYS_NO_PATHCONV"); + + if (no_pathconv) { + *src = end; + return NONE; + } + /* Let's not convert ~/.file to ~C:\msys64\.file */ if (*it == '~') { skip_p2w: From b2391806dbe3f72235fe1431940631f26757a2f0 Mon Sep 17 00:00:00 2001 From: Ray Donnelly Date: Fri, 21 Aug 2015 12:52:09 +0100 Subject: [PATCH 072/116] dcrt0.cc: Untangle allow_glob from winshell Otherwise if globbing is allowed and we get called from a Windows program, build_argv thinks we've been called from a Cygwin program. --- winsup/cygwin/dcrt0.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 16b624eab5..3536e80730 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -154,12 +154,12 @@ isquote (char c) /* Step over a run of characters delimited by quotes */ static /*__inline*/ char * -quoted (char *cmd, int winshell) +quoted (char *cmd, int winshell, int glob) { char *p; char quote = *cmd; - if (!winshell) + if (!winshell || !glob) { char *p; strcpy (cmd, cmd + 1); @@ -169,8 +169,8 @@ quoted (char *cmd, int winshell) } const char *s = quote == '\'' ? "'" : "\\\""; - /* This must have been run from a Windows shell, so preserve - quotes for globify to play with later. */ + /* This must have been run from a Windows shell and globbing is enabled, + so preserve quotes for globify to play with later. */ while (*cmd && *++cmd) if ((p = strpbrk (cmd, s)) == NULL) { @@ -292,7 +292,7 @@ globify (char *word, char **&argv, int &argc, int &argvlen) /* Build argv, argc from string passed from Windows. */ static void -build_argv (char *cmd, char **&argv, int &argc, int winshell) +build_argv (char *cmd, char **&argv, int &argc, int winshell, int glob) { int argvlen = 0; int nesting = 0; // monitor "nesting" from insert_file @@ -326,7 +326,7 @@ build_argv (char *cmd, char **&argv, int &argc, int winshell) a Cygwin process, or if the word starts with a '@'. In this case, the insert_file function needs an unquoted DOS filename and globbing isn't performed anyway. */ - cmd = quoted (cmd, winshell && argc > 0 && *word != '@'); + cmd = quoted (cmd, winshell && argc > 0 && *word != '@', glob); } if (issep (*cmd)) // End of argument if space break; @@ -352,7 +352,7 @@ build_argv (char *cmd, char **&argv, int &argc, int winshell) } /* Add word to argv file after (optional) wildcard expansion. */ - if (!winshell || !argc || !globify (word, argv, argc, argvlen)) + if (!glob || !argc || !globify (word, argv, argc, argvlen)) { debug_printf ("argv[%d] = '%s'", argc, word); argv[argc++] = word; @@ -907,6 +907,7 @@ dll_crt0_1 (void *) /* Scan the command line and build argv. Expand wildcards if not called from another cygwin process. */ build_argv (line, __argv, __argc, + NOTSTATE (myself, PID_CYGPARENT), NOTSTATE (myself, PID_CYGPARENT) && allow_glob); /* Convert argv[0] to posix rules if it's currently blatantly From 1e94f3ee1dc663bc0292324bef65be88c74c30fa Mon Sep 17 00:00:00 2001 From: Ray Donnelly Date: Mon, 24 Aug 2015 00:48:06 +0100 Subject: [PATCH 073/116] dcrt0.cc (globify): Don't quote literal strings differently when dos_spec Reverts 25ba8f306f3099caf8397859019e936b90510e8d. I can't figure out what the intention was. I'm sure I'll find out soon enough when everything breaks. This change means that input of: '"C:/test.exe SOME_VAR=\"literal quotes\""' becomes: 'C:/test.exe SOME_VAR="literal quotes"' instead of: 'C:/test.exe SOME_VAR=\literal quotes\' .. which is at least consistent with the result for: '"no_drive_or_colon SOME_VAR=\"literal quotes\""' The old result of course resulted in the quoted string being split into two arguments at the space which is clearly not intended. I *guess* backslashes in dos paths may have been the issue here? If so I don't care since we should not use them, ever, esp. not at the expense of sensible forward-slash-containing input. --- winsup/cygwin/dcrt0.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 3536e80730..81031cae8a 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -237,10 +237,20 @@ globify (char *word, char **&argv, int &argc, int &argvlen) while (*++s && *s != quote) { mbstate_t mbs = { 0 }; + /* This used to be: if (dos_spec || *s != '\\') - /* nothing */; + // nothing else if (s[1] == quote || s[1] == '\\') s++; + With commit message: + dcrt0.cc (globify): Don't use \ quoting when apparently quoting a DOS path + spec, even within a quoted string. + But that breaks the "literal quotes" part of '"C:/test.exe SOME_VAR=\"literal quotes\""' + giving: 'C:/test.exe SOME_VAR=\literal quotes\' (with \'s between each character) + instead of 'C:/test.exe SOME_VAR="literal quotes"' (with \'s between each character) + */ + if (*s == '\\' && (s[1] == quote || s[1] == '\\')) + s++; *p++ = '\\'; size_t cnt = isascii (*s) ? 1 : mbrtowi (NULL, s, MB_CUR_MAX, &mbs); if (cnt <= 1 || cnt == (size_t)-1) From e6c5e3ec30c0c99d797b69314d5721eaca2d752b Mon Sep 17 00:00:00 2001 From: Ray Donnelly Date: Fri, 21 Aug 2015 12:18:52 +0100 Subject: [PATCH 074/116] Add debugging for build_argv --- winsup/cygwin/dcrt0.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 81031cae8a..0a5c817b3c 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -311,6 +311,8 @@ build_argv (char *cmd, char **&argv, int &argc, int winshell, int glob) argvlen = 0; argv = NULL; + debug_printf ("cmd = '%s', winshell = %d, glob = %d", cmd, winshell, glob); + /* Scan command line until there is nothing left. */ while (*cmd) { From d44fc10030e02b339fe4253b2cf3d6d3e72e5c92 Mon Sep 17 00:00:00 2001 From: Ray Donnelly Date: Sun, 10 Apr 2016 21:47:41 +0100 Subject: [PATCH 075/116] environ.cc: New facility/environment variable MSYS2_ENV_CONV_EXCL Works very much like MSYS2_ARG_CONV_EXCL. In fact it uses the same function, arg_heuristic_with_exclusions (). Also refactors parsing the env. variables to use new function, string_split_delimited (). The env. that is searched through is the merged (POSIX + Windows) one. It remains to be seen if this should be made an option or not. This feature was prompted because the R language (Windows exe) calls bash to run configure.win, which then calls back into R to read its config variables (LOCAL_SOFT) and when this happens, msys2-runtime converts R_ARCH from "/x64" to an absolute Windows path and appends it to another absolute path, R_HOME, forming an invalid path. --- winsup/cygwin/environ.cc | 34 +++++++++++++++++------- winsup/cygwin/local_includes/miscfuncs.h | 2 ++ winsup/cygwin/miscfuncs.cc | 20 ++++++++++++++ winsup/cygwin/path.cc | 1 - winsup/cygwin/spawn.cc | 12 ++------- 5 files changed, 48 insertions(+), 21 deletions(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 117531367e..a9cce9645a 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -1173,6 +1173,10 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, int tl = 0; char **pass_dstp; +#ifdef __MSYS__ + char *msys2_env_conv_excl_env = NULL; + size_t msys2_env_conv_excl_count = 0; +#endif char **pass_env = (char **) alloca (sizeof (char *) * (n + winnum + SPENVS_SIZE + 1)); /* Iterate over input list, generating a new environment list and refreshing @@ -1181,16 +1185,25 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, { bool calc_tl = !no_envblock; #ifdef __MSYS__ - /* Don't pass timezone environment to non-msys applications */ - if (!keep_posix && ascii_strncasematch(*srcp, "TZ=", 3)) + if (!keep_posix) { - const char *v = *srcp + 3; - if (*v == ':') - goto next1; - for (; *v; v++) - if (!isalpha(*v) && !isdigit(*v) && - *v != '-' && *v != '+' && *v != ':') - goto next1; + /* Don't pass timezone environment to non-msys applications */ + if (ascii_strncasematch(*srcp, "TZ=", 3)) + { + const char *v = *srcp + 3; + if (*v == ':') + goto next1; + for (; *v; v++) + if (!isalpha(*v) && !isdigit(*v) && + *v != '-' && *v != '+' && *v != ':') + goto next1; + } + else if (ascii_strncasematch(*srcp, "MSYS2_ENV_CONV_EXCL=", 20)) + { + msys2_env_conv_excl_env = (char*)alloca (strlen(&(*srcp)[20])+1); + strcpy (msys2_env_conv_excl_env, &(*srcp)[20]); + msys2_env_conv_excl_count = string_split_delimited (msys2_env_conv_excl_env, ';'); + } } #endif /* Look for entries that require special attention */ @@ -1315,7 +1328,8 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, } #ifdef __MSYS__ else if (!keep_posix) { - char *win_arg = arg_heuristic(*srcp); + char *win_arg = arg_heuristic_with_exclusions + (*srcp, msys2_env_conv_excl_env, msys2_env_conv_excl_count); debug_printf("WIN32_PATH is %s", win_arg); p = cstrdup1(win_arg); if (win_arg != *srcp) diff --git a/winsup/cygwin/local_includes/miscfuncs.h b/winsup/cygwin/local_includes/miscfuncs.h index d52debad1a..c4dbe0235b 100644 --- a/winsup/cygwin/local_includes/miscfuncs.h +++ b/winsup/cygwin/local_includes/miscfuncs.h @@ -81,6 +81,8 @@ void backslashify (const char *, char *, bool); void slashify (const char *, char *, bool); #define isslash(c) ((c) == '/') +size_t string_split_delimited (char * string, char delimiter); + extern void transform_chars (PWCHAR, PWCHAR); extern inline void transform_chars (PUNICODE_STRING upath, USHORT start_idx) diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc index 4220f62757..5446654389 100644 --- a/winsup/cygwin/miscfuncs.cc +++ b/winsup/cygwin/miscfuncs.cc @@ -311,6 +311,26 @@ NT_readline::gets () } } +/* Searches through string for delimiter replacing each instance with '\0' + and returning the number of such delimited substrings. This function + Will return 0 for the NULL string and at least 1 otherwise. */ + +size_t +string_split_delimited (char * string, char delimiter) +{ + if ( string == NULL ) + return 0; + size_t count = 1; + string = strchr ( string, delimiter ); + while (string) + { + *string = '\0'; + ++count; + string = strchr ( string + 1, delimiter ); + } + return count; +} + /* Signal the thread name to any attached debugger (See "How to: Set a Thread Name in Native Code" diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index b1a088a9fd..39819dc694 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -4051,7 +4051,6 @@ arg_heuristic_with_exclusions (char const * const arg, char const * exclusions, return arg_result; } - debug_printf("Input value: (%s)", arg); for (size_t excl = 0; excl < exclusions_count; ++excl) { /* Since we've got regex linked we should maybe switch to that, but diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index d7affaac88..5b3cbeb90f 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -293,8 +293,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, int res = -1; /* Environment variable MSYS2_ARG_CONV_EXCL contains a list - of ';' separated argument prefixes to pass un-modified.. - It isn't applied to env. variables; only spawn arguments. + of ';' separated argument prefixes to pass un-modified. A value of * means don't convert any arguments. */ char* msys2_arg_conv_excl_env = getenv("MSYS2_ARG_CONV_EXCL"); char* msys2_arg_conv_excl = NULL; @@ -303,14 +302,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, { msys2_arg_conv_excl = (char*)alloca (strlen(msys2_arg_conv_excl_env)+1); strcpy (msys2_arg_conv_excl, msys2_arg_conv_excl_env); - msys2_arg_conv_excl_count = 1; - msys2_arg_conv_excl_env = strchr ( msys2_arg_conv_excl, ';' ); - while (msys2_arg_conv_excl_env) - { - *msys2_arg_conv_excl_env = '\0'; - ++msys2_arg_conv_excl_count; - msys2_arg_conv_excl_env = strchr ( msys2_arg_conv_excl_env + 1, ';' ); - } + msys2_arg_conv_excl_count = string_split_delimited (msys2_arg_conv_excl, ';'); } /* Check if we have been called from exec{lv}p or spawn{lv}p and mask From 98c164175f51d79bc91caaad905b386e8d45615b Mon Sep 17 00:00:00 2001 From: SquallATF Date: Mon, 10 Sep 2018 11:32:18 +0300 Subject: [PATCH 076/116] Fix native symbolic link spawn passing wrong arg0 --- winsup/cygwin/spawn.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index 5b3cbeb90f..b97c6da3ed 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -50,7 +50,7 @@ perhaps_suffix (const char *prog, path_conv& buf, int& err, unsigned opt) err = 0; debug_printf ("prog '%s'", prog); - buf.check (prog, PC_SYM_FOLLOW | PC_NULLEMPTY | PC_POSIX, + buf.check (prog, PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP | PC_NULLEMPTY | PC_POSIX, (opt & FE_DLL) ? stat_suffixes : exe_suffixes); if (buf.isdir ()) From d12ab6d59cbc9473f29afdf2bd12318a1a5f09ea Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 19 May 2020 13:49:37 +0200 Subject: [PATCH 077/116] Introduce the `enable_pcon` value for `MSYS` It is simply the negation of `disable_pcon`, i.e. `MSYS=enable_pcon` is equivalent to `MSYS=nodisable_pcon` (the former is slightly more intuitive than the latter) and likewise `MSYS=noenable_pcon` is equivalent to `MSYS=disable_pcon` (here, the latter is definitely more intuitive than the former). This is needed because we just demoted the pseudo console feature to be opt-in instead of opt-out, and it would be awkward to recommend to users to use "nodisable_pcon"... "nodisable" is not even a verb. Signed-off-by: Johannes Schindelin --- winsup/cygwin/environ.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index a9cce9645a..b9600ef9a8 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -42,6 +42,7 @@ enum settings isfunc, setdword, setbool, + setnegbool, setbit }; @@ -118,6 +119,7 @@ static struct parse_thing } known[] NO_COPY = { {"disable_pcon", {&disable_pcon}, setbool, NULL, {{false}, {true}}}, + {"enable_pcon", {&disable_pcon}, setnegbool, NULL, {{true}, {false}}}, {"error_start", {func: error_start_init}, isfunc, NULL, {{0}, {0}}}, {"export", {&export_settings}, setbool, NULL, {{false}, {true}}}, {"glob", {func: glob_init}, isfunc, NULL, {{0}, {s: "normal"}}}, @@ -244,6 +246,13 @@ parse_options (const char *inbuf) *k->setting.b = !!strtol (eq, NULL, 0); debug_printf ("%s%s", *k->setting.b ? "" : "no", k->name); break; + case setnegbool: + if (!istrue || !eq) + *k->setting.b = k->values[istrue].i; + else + *k->setting.b = !strtol (eq, NULL, 0); + debug_printf ("%s%s", !*k->setting.b ? "" : "no", k->name); + break; case setbit: *k->setting.x &= ~k->values[istrue].i; if (istrue || (eq && strtol (eq, NULL, 0))) From 865ad5d64ececf728b8027043684b5e2a4e9ae2a Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Fri, 5 Jun 2020 20:09:11 +0200 Subject: [PATCH 078/116] popen: call /usr/bin/sh instead of /bin/sh We mount /usr/bin to /bin, but in a chroot this is broken and we have no /bin, so try to use the real path. chroot is used by pacman to run install scripts when called with --root and this broke programs in install scripts calling popen() (install-info from texinfo for example) There are more paths hardcoded to /bin in cygwin which might also be broken in this scenario, so this maybe should be extended to all of them. --- winsup/cygwin/syscalls.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 2d7071bd6b..e584e960a7 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -4425,7 +4425,7 @@ popen (const char *command, const char *in_type) fcntl (stdchild, F_SETFD, stdchild_state | FD_CLOEXEC); /* Start a shell process to run the given command without forking. */ - pid_t pid = ch_spawn.worker ("/bin/sh", argv, environ, _P_NOWAIT, + pid_t pid = ch_spawn.worker ("/usr/bin/sh", argv, environ, _P_NOWAIT, __std[0], __std[1]); /* Reinstate the close-on-exec state */ From 5f36fdbfcd97d3db2d03676641373360fa919dad Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 17 Mar 2021 17:41:02 +0100 Subject: [PATCH 079/116] Disable the 'cygwin' GitHub workflow It does not work at all. For example, `rpm -E %fedora` says that there should be version 33 of rpmsphere at https://github.com/rpmsphere/noarch/tree/master/r, but there is only version 32. Another thing that is broken: Cygwin now assumes that a recent mingw-w64-headers version is available, but Fedora apparently only offers v7.0.0, which is definitely too old to accommodate for the expectation of https://github.com/cygwin/cygwin/commit/c1f7c4d1b6d7. Signed-off-by: Johannes Schindelin --- .github/workflows/cygwin.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/cygwin.yml b/.github/workflows/cygwin.yml index be377bb3b1..5ae4ef9d59 100644 --- a/.github/workflows/cygwin.yml +++ b/.github/workflows/cygwin.yml @@ -1,12 +1,6 @@ name: cygwin -on: - push: - # since master is a symbolic reference to main, don't run for both - branches-ignore: - - 'master' - tags: - - '*' +on: workflow_dispatch jobs: fedora-build: From 862887f29f656deaad0d2b08de997d9279531d16 Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Sun, 9 Aug 2020 14:02:51 +0200 Subject: [PATCH 080/116] CI: add a GHA for doing a basic build test Build with --disable-dependency-tracking because we only build once and this saves 3-4 minutes in CI. --- .github/workflows/build.yaml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/build.yaml diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000000..4e96696182 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,36 @@ +name: build + +on: [push, pull_request] + +jobs: + build: + runs-on: windows-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: setup-msys2 + uses: msys2/setup-msys2@v2 + with: + msystem: MSYS + update: true + install: msys2-devel base-devel autotools cocom diffutils gcc gettext-devel libiconv-devel make mingw-w64-cross-crt mingw-w64-cross-gcc mingw-w64-cross-zlib perl zlib-devel xmlto docbook-xsl + + - name: Build + shell: msys2 {0} + run: | + (cd winsup && ./autogen.sh) + ./configure --disable-dependency-tracking + make -j8 + + - name: Install + shell: msys2 {0} + run: | + make DESTDIR="$(pwd)"/_dest install + + - name: Upload + uses: actions/upload-artifact@v4 + with: + name: install + path: _dest/ From 764bd7fb8fd3b6f9574b35b4fd92ab063d0879a5 Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Fri, 10 Nov 2023 15:31:10 +0100 Subject: [PATCH 081/116] CI: fix the build with gcc 13 --- .github/workflows/build.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 4e96696182..5e11108335 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -20,6 +20,9 @@ jobs: - name: Build shell: msys2 {0} run: | + # XXX: cygwin still uses gcc v11 so we get new warnings with v13, + # resulting in errors due to -Werror. Disable them for now. + export CXXFLAGS="-Wno-error=stringop-truncation -Wno-error=array-bounds -Wno-error=overloaded-virtual -Wno-narrowing -Wno-use-after-free" (cd winsup && ./autogen.sh) ./configure --disable-dependency-tracking make -j8 From bea6a078cafb36110dad140cfd926841a9c7a47c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 22 Nov 2019 11:20:22 +0100 Subject: [PATCH 082/116] Set up a GitHub Action to keep in sync with Cygwin This will help us by automating an otherwise tedious task. Signed-off-by: Johannes Schindelin --- .github/workflows/sync-with-cygwin.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/sync-with-cygwin.yml diff --git a/.github/workflows/sync-with-cygwin.yml b/.github/workflows/sync-with-cygwin.yml new file mode 100644 index 0000000000..57bd30e5da --- /dev/null +++ b/.github/workflows/sync-with-cygwin.yml @@ -0,0 +1,24 @@ +name: sync-with-cygwin + +# File: .github/workflows/repo-sync.yml + +on: + workflow_dispatch: + schedule: + - cron: "42 * * * *" +jobs: + repo-sync: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Fetch Cygwin's latest master and tags + run: | + git init --bare + # Potentially use git://sourceware.org/git/newlib-cygwin.git directly, but GitHub seems more reliable + git fetch https://github.com/cygwin/cygwin master:refs/heads/cygwin/master 'refs/tags/*:refs/tags/*' + - name: Push to our fork + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git push https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY refs/heads/cygwin/master 'refs/tags/*:refs/tags/*' From 080e2b0f6abe07f4eab5e44bf689f3f48efc7b61 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 12 Aug 2020 12:22:38 +0200 Subject: [PATCH 083/116] Expose full command-lines to other Win32 processes by default In the Cygwin project, it was decided that the command-line of Cygwin processes, as shown in the output of `wmic process list`, would suffer from being truncated to 32k (and is transmitted to the child process via a different mechanism, anyway), and therefore only the absolute path of the executable is shown by default. Users who would like to see the full command-line (even if it is truncated) are expected to set `CYGWIN=wincmdln` (or, in MSYS2's case, `MSYS=wincmdln`). Seeing as MSYS2 tries to integrate much better with the surrounding Win32 ecosystem than Cygwin, it makes sense to turn this on by default. Users who wish to suppress it can still set `MSYS=nowincmdln`. Signed-off-by: Johannes Schindelin --- winsup/cygwin/globals.cc | 2 +- winsup/doc/cygwinenv.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/winsup/cygwin/globals.cc b/winsup/cygwin/globals.cc index 0c21fa624e..b3b77de405 100644 --- a/winsup/cygwin/globals.cc +++ b/winsup/cygwin/globals.cc @@ -70,7 +70,7 @@ bool allow_glob = true; bool ignore_case_with_glob; bool pipe_byte = true; /* Default to byte mode so that C# programs work. */ bool reset_com; -bool wincmdln; +bool wincmdln = true; winsym_t allow_winsymlinks = WSYM_deepcopy; bool disable_pcon; bool winjitdebug = false; diff --git a/winsup/doc/cygwinenv.xml b/winsup/doc/cygwinenv.xml index fcb6e22485..4ea63b407a 100644 --- a/winsup/doc/cygwinenv.xml +++ b/winsup/doc/cygwinenv.xml @@ -90,7 +90,7 @@ time and when handles are inherited. Defaults to set. (no)wincmdln - if set, the windows complete command line (truncated to ~32K) will be passed on any processes that it creates -in addition to the normal UNIX argv list. Defaults to not set. +in addition to the normal UNIX argv list. Defaults to set. From 9f45f58388505943f06fff68c8695dd5f17d2a67 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Apr 2018 14:59:39 +0200 Subject: [PATCH 084/116] Add a helper to obtain a function's address in kernel32.dll In particular, we are interested in the address of the CtrlRoutine and the ExitProcess functions. Since kernel32.dll is loaded first thing, the addresses will be the same for all processes (matching the CPU architecture, of course). This will help us with emulating SIGINT properly (by not sending signals to *all* processes attached to the same Console, as GenerateConsoleCtrlEvent() would do). Co-authored-by: Naveen M K Signed-off-by: Johannes Schindelin --- winsup/configure.ac | 5 + winsup/utils/mingw/Makefile.am | 15 ++ winsup/utils/mingw/getprocaddr.c | 310 +++++++++++++++++++++++++++++++ 3 files changed, 330 insertions(+) create mode 100644 winsup/utils/mingw/getprocaddr.c diff --git a/winsup/configure.ac b/winsup/configure.ac index 9b9b59dbcb..b9e3977fcf 100644 --- a/winsup/configure.ac +++ b/winsup/configure.ac @@ -106,6 +106,11 @@ if test "x$with_cross_bootstrap" != "xyes"; then test -n "$MINGW_CXX" || AC_MSG_ERROR([no acceptable MinGW g++ found in \$PATH]) AC_CHECK_PROGS(MINGW_CC, ${target_cpu}-w64-mingw32-gcc) test -n "$MINGW_CC" || AC_MSG_ERROR([no acceptable MinGW gcc found in \$PATH]) + + AC_CHECK_PROGS(MINGW32_CC, i686-w64-mingw32-gcc) + test -n "$MINGW32_CC" || AC_MSG_ERROR([no acceptable mingw32 gcc found in \$PATH]) + AC_CHECK_PROGS(MINGW64_CC, x86_64-w64-mingw32-gcc) + test -n "$MINGW64_CC" || AC_MSG_ERROR([no acceptable mingw64 gcc found in \$PATH]) fi AM_CONDITIONAL(CROSS_BOOTSTRAP, [test "x$with_cross_bootstrap" != "xyes"]) diff --git a/winsup/utils/mingw/Makefile.am b/winsup/utils/mingw/Makefile.am index 7f7317ae15..07b9f928d4 100644 --- a/winsup/utils/mingw/Makefile.am +++ b/winsup/utils/mingw/Makefile.am @@ -26,6 +26,21 @@ bin_PROGRAMS = \ ldh \ strace +libexec_PROGRAMS = getprocaddr32 getprocaddr64 + +# Must *not* use -O2 here, as it screws up the stack backtrace +getprocaddr32.o: %32.o: %.c + $(MINGW32_CC) -c -o $@ $< + +getprocaddr32.exe: %.exe: %.o + $(MINGW32_CC) -o $@ $^ -static -ldbghelp + +getprocaddr64.o: %64.o: %.c + $(MINGW64_CC) -c -o $@ $< + +getprocaddr64.exe: %.exe: %.o + $(MINGW64_CC) -o $@ $^ -static -ldbghelp + cygcheck_SOURCES = \ bloda.cc \ cygcheck.cc \ diff --git a/winsup/utils/mingw/getprocaddr.c b/winsup/utils/mingw/getprocaddr.c new file mode 100644 index 0000000000..25814c7bdd --- /dev/null +++ b/winsup/utils/mingw/getprocaddr.c @@ -0,0 +1,310 @@ +/* getprocaddr.c + +This program is a helper for getting the pointers for the +functions in kernel32 module, and optionally injects a remote +thread that runs those functions given a pid and exit code. + +We use dbghelp.dll to get the pointer to kernel32!CtrlRoutine +because it isn't exported. For that, we try to generate console +event (Ctrl+Break) ourselves, to find the pointer, and it is +printed if asked to, or a remote thread is injected to run the +given function. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include + +/* Include dbghelp.h after windows.h */ +#include + +static DWORD pid; +static uintptr_t exit_code; +static HANDLE CtrlEvent; + +static int +inject_remote_thread_into_process (HANDLE process, + LPTHREAD_START_ROUTINE address, + uintptr_t exit_code, + DWORD *thread_return) +{ + int res = -1; + + if (!address) + return res; + DWORD thread_id; + HANDLE thread = CreateRemoteThread (process, NULL, 1024 * 1024, address, + (PVOID)exit_code, 0, &thread_id); + if (thread) + { + /* + * Wait up to 10 seconds (arbitrary constant) for the thread to finish; + * Maybe we should wait forever? I have seen Cmd does so, but well... + */ + if (WaitForSingleObject (thread, 10000) == WAIT_OBJECT_0) + res = 0; + /* + According to the docs at MSDN for GetExitCodeThread, it will + get the return value from the function, here CtrlRoutine. So, this + checks if the Ctrl Event is handled correctly by the process. + + By some testing I could see CtrlRoutine returns 0 in case where + CtrlEvent set by SetConsoleCtrlHandler is handled correctly, in all + other cases it returns something non-zero(not sure what it that). + */ + if (thread_return != NULL) + GetExitCodeThread (thread, thread_return); + + CloseHandle (thread); + } + + return res; +} + +/* Here, we send a CtrlEvent to the current process for the + * sole purpose of capturing the address of the CtrlRoutine + * function, by looking the stack trace. + * + * This hack is needed because we cannot use GetProcAddress() + * as we do for ExitProcess(), because CtrlRoutine is not + * exported (although the .pdb files ensure that we can see + * it in a debugger). + */ +static WINAPI BOOL +ctrl_handler (DWORD ctrl_type) +{ + unsigned short count; + void *address; + HANDLE process; + PSYMBOL_INFOW info; + DWORD64 displacement; + DWORD thread_return = 0; + + count = CaptureStackBackTrace (1l /* skip this function */, + 1l /* return only one trace item */, &address, + NULL); + if (count != 1) + { + fprintf (stderr, "Could not capture backtrace\n"); + return FALSE; + } + + process = GetCurrentProcess (); + if (!SymInitialize (process, NULL, TRUE)) + { + fprintf (stderr, "Could not initialize symbols\n"); + return FALSE; + } + + info = (PSYMBOL_INFOW)malloc (sizeof (*info) + + MAX_SYM_NAME * sizeof (wchar_t)); + if (!info) + { + fprintf (stderr, "Could not allocate symbol info structure\n"); + return FALSE; + } + info->SizeOfStruct = sizeof (*info); + info->MaxNameLen = MAX_SYM_NAME; + + if (!SymFromAddrW (process, (DWORD64) (intptr_t)address, &displacement, + info)) + { + fprintf (stderr, "Could not get symbol info\n"); + SymCleanup (process); + return FALSE; + } + + if (pid == 0) + { + printf ("%p\n", (void *)(intptr_t)info->Address); + } + else + { + LPTHREAD_START_ROUTINE address = + (LPTHREAD_START_ROUTINE) (intptr_t)info->Address; + HANDLE h = OpenProcess (PROCESS_CREATE_THREAD | + PROCESS_QUERY_INFORMATION | + PROCESS_VM_OPERATION | + PROCESS_VM_WRITE | + PROCESS_VM_READ, FALSE, pid); + if (h == NULL) + { + fprintf (stderr, "OpenProcess failed: %ld\n", GetLastError ()); + return 1; + } + /* Inject the remote thread only when asked to */ + if (inject_remote_thread_into_process (h, address, exit_code, + &thread_return) < 0) + { + fprintf (stderr, + "Error while injecting remote thread for pid(%lu)\n", pid); + exit (1); /*We should exit immediately or else there will a 10s hang + waiting for the event to happen.*/ + } + if (thread_return) + fprintf (stderr, + "Injected remote thread for pid(%lu) returned %lu\n", pid, + thread_return); + } + SymCleanup (process); + if (!SetEvent (CtrlEvent)) + { + fprintf (stderr, "SetEvent failed (%ld)\n", GetLastError ()); + return 1; + } + exit (thread_return != 0); +} + +/* The easy route for finding the address of CtrlRoutine + * would be use GetProcAddress() but this isn't viable + * here because that symbol isn't exported. + */ +static int +find_ctrl_routine_the_hard_way () +{ + /* + * Avoid terminating all processes attached to the current console; + * This would happen if we used the same console as the caller, though, + * because we are sending a CtrlEvent on purpose (which _is_ sent to + * all processes connected to the same console, and the other processes + * are most likely unprepared for that CTRL_BREAK_EVENT and would be + * terminated as a consequence, _including the caller_). + * + * In case we get only one result from GetConsoleProcessList(), we don't + * need to create and allocate a new console, and it could avoid a console + * window popping up. + */ + DWORD proc_lists; + if (GetConsoleProcessList (&proc_lists, 5) > 1) + { + if (!FreeConsole () && GetLastError () != ERROR_INVALID_PARAMETER) + { + fprintf (stderr, "Could not detach from current Console: %ld\n", + GetLastError ()); + return 1; + } + if (!AllocConsole ()) + { + fprintf (stderr, "Could not allocate a new Console\n"); + return 1; + } + } + + CtrlEvent = CreateEvent (NULL, // default security attributes + TRUE, // manual-reset event + FALSE, // initial state is nonsignaled + NULL // object name + ); + + if (CtrlEvent == NULL) + { + fprintf (stderr, "CreateEvent failed (%ld)\n", GetLastError ()); + return 1; + } + + + if (!SetConsoleCtrlHandler (ctrl_handler, TRUE)) + { + fprintf (stderr, "Could not register Ctrl handler\n"); + return 1; + } + + if (!GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, 0)) + { + fprintf (stderr, "Could not simulate Ctrl+Break\n"); + return 1; + } + + if (WaitForSingleObject (CtrlEvent, 10000 /* 10 seconds*/) != WAIT_OBJECT_0) + { + fprintf (stderr, "WaitForSingleObject failed (%ld)\n", GetLastError ()); + return 1; + } + return 0; +} + +static void * +get_proc_addr (const char * module_name, const char * function_name) +{ + HMODULE module = GetModuleHandle (module_name); + if (!module) + return NULL; + return (void *)GetProcAddress (module, function_name); +} + +int +main (int argc, char **argv) +{ + char *end; + void *address; + BOOL is_ctrl_routine; + DWORD thread_return = 0; + + if (argc == 4) + { + exit_code = atoi (argv[2]); + pid = strtoul (argv[3], NULL, 0); + } + else if (argc == 2) + { + pid = 0; + } + else + { + fprintf (stderr, "Need a function name, exit code and pid\n" + "Or needs a function name.\n"); + return 1; + } + + is_ctrl_routine = strcmp (argv[1], "CtrlRoutine") == 0; + address = get_proc_addr ("kernel32", argv[1]); + if (is_ctrl_routine && !address) + { + /* CtrlRoutine is undocumented, and has been seen in both + * kernel32 and kernelbase + */ + address = get_proc_addr ("kernelbase", argv[1]); + if (!address) + return find_ctrl_routine_the_hard_way (); + } + + if (!address) + { + fprintf (stderr, "Could not get proc address\n"); + return 1; + } + + if (pid == 0) + { + printf ("%p\n", address); + fflush (stdout); + return 0; + } + HANDLE h = OpenProcess (PROCESS_CREATE_THREAD | + PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | + PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, pid); + if (h == NULL) + { + fprintf (stderr, "OpenProcess failed: %ld\n", GetLastError ()); + return 1; + } + /* Inject the remote thread */ + if (inject_remote_thread_into_process (h, (LPTHREAD_START_ROUTINE)address, + exit_code, &thread_return) < 0) + { + fprintf (stderr, "Could not inject thread into process %lu\n", pid); + return 1; + } + + if (is_ctrl_routine && thread_return) + { + fprintf (stderr, + "Injected remote thread for pid %lu returned %lu\n", pid, + thread_return); + return 1; + } + + return 0; +} From f6f7e2c92880e56d0c4b8712630941aa72257f4d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 20 Mar 2015 09:56:28 +0000 Subject: [PATCH 085/116] Emulate GenerateConsoleCtrlEvent() upon Ctrl+C This patch is heavily inspired by the Git for Windows' strategy in handling Ctrl+C. When a process is terminated via TerminateProcess(), it has no chance to do anything in the way of cleaning up. This is particularly noticeable when a lengthy Git for Windows process tries to update Git's index file and leaves behind an index.lock file. Git's idea is to remove the stale index.lock file in that case, using the signal and atexit handlers available in Linux. But those signal handlers never run. Note: this is not an issue for MSYS2 processes because MSYS2 emulates Unix' signal system accurately, both for the process sending the kill signal and the process receiving it. Win32 processes do not have such a signal handler, though, instead MSYS2 shuts them down via `TerminateProcess()`. For a while, Git for Windows tried to use a gentler method, described in the Dr Dobb's article "A Safer Alternative to TerminateProcess()" by Andrew Tucker (July 1, 1999), http://www.drdobbs.com/a-safer-alternative-to-terminateprocess/184416547 Essentially, we injected a new thread into the running process that does nothing else than running the ExitProcess() function. However, this was still not in line with the way CMD handles Ctrl+C: it gives processes a chance to do something upon Ctrl+C by calling SetConsoleCtrlHandler(), and ExitProcess() simply never calls that handler. So for a while we tried to handle SIGINT/SIGTERM by attaching to the console of the command to interrupt, and generating the very same event as CMD does via GenerateConsoleCtrlEvent(). This method *still* was not correct, though, as it would interrupt *every* process attached to that Console, not just the process (and its children) that we wanted to signal. A symptom was that hitting Ctrl+C while `git log` was shown in the pager would interrupt *the pager*. The method we settled on is to emulate what GenerateConsoleCtrlEvent() does, but on a process by process basis: inject a remote thread and call the (private) function kernel32!CtrlRoutine. To obtain said function's address, we use the dbghelp API to generate a stack trace from a handler configured via SetConsoleCtrlHandler() and triggered via GenerateConsoleCtrlEvent(). To avoid killing each and all processes attached to the same Console as the MSYS2 runtime, we modify the cygwin-console-helper to optionally print the address of kernel32!CtrlRoutine to stdout, and then spawn it with a new Console. Note that this also opens the door to handling 32-bit process from a 64-bit MSYS2 runtime and vice versa, by letting the MSYS2 runtime look for the cygwin-console-helper.exe of the "other architecture" in a specific place (we choose /usr/libexec/, as it seems to be the convention for helper .exe files that are not intended for public consumption). The 32-bit helper implicitly links to libgcc_s_dw2.dll and libwinpthread-1.dll, so to avoid cluttering /usr/libexec/, we look for the helped of the "other" architecture in the corresponding mingw32/ or mingw64/ subdirectory. Among other bugs, this strategy to handle Ctrl+C fixes the MSYS2 side of the bug where interrupting `git clone https://...` would send the spawned-off `git remote-https` process into the background instead of interrupting it, i.e. the clone would continue and its progress would be reported mercilessly to the console window without the user being able to do anything about it (short of firing up the task manager and killing the appropriate task manually). Note that this special-handling is only necessary when *MSYS2* handles the Ctrl+C event, e.g. when interrupting a process started from within MinTTY or any other non-cmd-based terminal emulator. If the process was started from within `cmd.exe`'s terminal window, child processes are already killed appropriately upon Ctrl+C, by `cmd.exe` itself. Also, we can't trust the processes to end it's subprocesses upon receiving Ctrl+C. For example, `pip.exe` from `python-pip` doesn't kill the python it lauches (it tries to but fails), and I noticed that in cmd it kills python also correctly, which mean we should kill all the process using `exit_process_tree`. Co-authored-by: Naveen M K Signed-off-by: Johannes Schindelin --- winsup/cygwin/exceptions.cc | 24 +- winsup/cygwin/include/cygwin/exit_process.h | 364 ++++++++++++++++++++ 2 files changed, 384 insertions(+), 4 deletions(-) create mode 100644 winsup/cygwin/include/cygwin/exit_process.h diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 85909290a3..469052a98a 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -29,6 +29,7 @@ details. */ #include "exception.h" #include "posix_timer.h" #include "gcc_seh.h" +#include "cygwin/exit_process.h" /* Define macros for CPU-agnostic register access. The _CX_foo macros are for access into CONTEXT, the _MC_foo ones for access into @@ -1605,10 +1606,25 @@ sigpacket::process () dosig: if (have_execed) { - sigproc_printf ("terminating captive process"); - if (::cygheap->ctty) - ::cygheap->ctty->cleanup_before_exit (); - TerminateProcess (ch_spawn, sigExeced = si.si_signo); + switch (si.si_signo) + { + case SIGUSR1: + case SIGUSR2: + case SIGCONT: + case SIGSTOP: + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + system_printf ("Suppressing signal %d to win32 process (pid %u)", + (int)si.si_signo, (unsigned int)GetProcessId(ch_spawn)); + goto done; + default: + sigproc_printf ("terminating captive process"); + if (::cygheap->ctty) + ::cygheap->ctty->cleanup_before_exit (); + rc = exit_process_tree (ch_spawn, 128 + (sigExeced = si.si_signo)); + goto done; + } } /* Dispatch to the appropriate function. */ sigproc_printf ("signal %d, signal handler %p", si.si_signo, handler); diff --git a/winsup/cygwin/include/cygwin/exit_process.h b/winsup/cygwin/include/cygwin/exit_process.h new file mode 100644 index 0000000000..0486a0c74a --- /dev/null +++ b/winsup/cygwin/include/cygwin/exit_process.h @@ -0,0 +1,364 @@ +#ifndef EXIT_PROCESS_H +#define EXIT_PROCESS_H + +/* + * This file contains functions to terminate a Win32 process, as gently as + * possible. + * + * If appropriate, we will attempt to emulate a console Ctrl event for the + * process. Otherwise we will fall back to terminating the process. + * + * As we do not want to export this function in the MSYS2 runtime, these + * functions are marked as file-local. + * + * The idea is to inject a thread into the given process that runs either + * kernel32!CtrlRoutine() (i.e. the work horse of GenerateConsoleCtrlEvent()) + * for SIGINT (Ctrl+C) and SIGQUIT (Ctrl+Break), or ExitProcess() for SIGTERM. + * This is handled through the console helpers. + * + * For SIGKILL, we run TerminateProcess() without injecting anything, and this + * is also the fall-back when the previous methods are unavailable. + * + * Note: as kernel32.dll is loaded before any process, the other process and + * this process will have ExitProcess() at the same address. The same holds + * true for kernel32!CtrlRoutine(), of course, but it is an internal API + * function, so we cannot look it up directly. Instead, we launch + * getprocaddr.exe to find out and inject the remote thread. + * + * This function expects the process handle to have the access rights for + * CreateRemoteThread(): PROCESS_CREATE_THREAD, PROCESS_QUERY_INFORMATION, + * PROCESS_VM_OPERATION, PROCESS_VM_WRITE, and PROCESS_VM_READ. + * + * The idea for the injected remote thread comes from the Dr Dobb's article "A + * Safer Alternative to TerminateProcess()" by Andrew Tucker (July 1, 1999), + * http://www.drdobbs.com/a-safer-alternative-to-terminateprocess/184416547. + * + * The idea to use kernel32!CtrlRoutine for the other signals comes from + * SendSignal (https://github.com/AutoSQA/SendSignal/ and + * http://stanislavs.org/stopping-command-line-applications-programatically-with-ctrl-c-events-from-net/). + */ + +#include +#include + +#ifndef __INSIDE_CYGWIN__ +/* To help debugging via kill.exe */ +#define small_printf(...) fprintf (stderr, __VA_ARGS__) +#endif + +static BOOL get_wow (HANDLE process, BOOL &is_wow, USHORT &process_arch); +static int exit_process_tree (HANDLE main_process, int exit_code); + +static BOOL +kill_via_console_helper (HANDLE process, wchar_t *function_name, int exit_code, + DWORD pid) +{ + BOOL is_wow; + USHORT process_arch; + if (!get_wow (process, is_wow, process_arch)) + { + return FALSE; + } + + const char *name; + switch (process_arch) + { + case IMAGE_FILE_MACHINE_I386: + name = "/usr/libexec/getprocaddr32.exe"; + break; + case IMAGE_FILE_MACHINE_AMD64: + name = "/usr/libexec/getprocaddr64.exe"; + break; + /* TODO: provide exes for these */ + case IMAGE_FILE_MACHINE_ARMNT: + name = "/usr/libexec/getprocaddrarm32.exe"; + break; + case IMAGE_FILE_MACHINE_ARM64: + name = "/usr/libexec/getprocaddrarm64.exe"; + break; + default: + return FALSE; /* what?!? */ + } + wchar_t wbuf[PATH_MAX]; + + if (cygwin_conv_path (CCP_POSIX_TO_WIN_W, name, wbuf, PATH_MAX) + || GetFileAttributesW (wbuf) == INVALID_FILE_ATTRIBUTES) + return FALSE; + + STARTUPINFOW si = {}; + PROCESS_INFORMATION pi; + size_t len = wcslen (wbuf) + 1 /* space */ + wcslen (function_name) + + 1 /* space */ + 3 /* exit code */ + 1 /* space */ + + 10 /* process ID, i.e. DWORD */ + 1 /* NUL */; + WCHAR cmd[len + 1]; + WCHAR title[] = L"cygwin-console-helper"; + DWORD process_exit; + + swprintf (cmd, len + 1, L"%S %S %d %u", wbuf, function_name, exit_code, + pid); + + si.cb = sizeof (si); + si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; + si.wShowWindow = SW_HIDE; + si.lpTitle = title; + si.hStdInput = si.hStdError = si.hStdOutput = INVALID_HANDLE_VALUE; + + /* Create a new hidden process. */ + if (!CreateProcessW (NULL, cmd, NULL, NULL, TRUE, + CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP, NULL, NULL, + &si, &pi)) + { + return FALSE; + } + else + { + /* Wait for the process to complete for 10 seconds */ + WaitForSingleObject (pi.hProcess, 10000); + } + + if (!GetExitCodeProcess (pi.hProcess, &process_exit)) + process_exit = -1; + + CloseHandle (pi.hThread); + CloseHandle (pi.hProcess); + + return process_exit == 0 ? TRUE : FALSE; +} + +static int current_is_wow = -1; +static int is_32_bit_os = -1; + +typedef BOOL (WINAPI * IsWow64Process2_t) (HANDLE, USHORT *, USHORT *); +static bool wow64process2initialized = false; +static IsWow64Process2_t pIsWow64Process2 /* = NULL */; + +typedef BOOL (WINAPI * GetProcessInformation_t) (HANDLE, + PROCESS_INFORMATION_CLASS, + LPVOID, DWORD); +static bool getprocessinfoinitialized = false; +static GetProcessInformation_t pGetProcessInformation /* = NULL */; + +static BOOL +get_wow (HANDLE process, BOOL &is_wow, USHORT &process_arch) +{ + USHORT native_arch = IMAGE_FILE_MACHINE_UNKNOWN; + if (!wow64process2initialized) + { + pIsWow64Process2 = (IsWow64Process2_t) + GetProcAddress (GetModuleHandle ("KERNEL32"), + "IsWow64Process2"); + MemoryBarrier (); + wow64process2initialized = true; + } + if (!pIsWow64Process2) + { + if (is_32_bit_os == -1) + { + SYSTEM_INFO info; + + GetNativeSystemInfo (&info); + if (info.wProcessorArchitecture == 0) + is_32_bit_os = 1; + else if (info.wProcessorArchitecture == 9) + is_32_bit_os = 0; + else + is_32_bit_os = -2; + } + + if (current_is_wow == -1 + && !IsWow64Process (GetCurrentProcess (), ¤t_is_wow)) + current_is_wow = -2; + + if (is_32_bit_os == -2 || current_is_wow == -2) + return FALSE; + + if (!IsWow64Process (process, &is_wow)) + return FALSE; + + process_arch = is_32_bit_os || is_wow ? IMAGE_FILE_MACHINE_I386 : + IMAGE_FILE_MACHINE_AMD64; + return TRUE; + } + + if (!pIsWow64Process2 (process, &process_arch, &native_arch)) + return FALSE; + + /* The value will be IMAGE_FILE_MACHINE_UNKNOWN if the target process + * is not a WOW64 process + */ + if (process_arch == IMAGE_FILE_MACHINE_UNKNOWN) + { + struct /* _PROCESS_MACHINE_INFORMATION */ + { + /* 0x0000 */ USHORT ProcessMachine; + /* 0x0002 */ USHORT Res0; + /* 0x0004 */ DWORD MachineAttributes; + } /* size: 0x0008 */ process_machine_info; + + is_wow = FALSE; + /* However, x86_64 on ARM64 claims not to be WOW64, so we have to + * dig harder... */ + if (!getprocessinfoinitialized) + { + pGetProcessInformation = (GetProcessInformation_t) + GetProcAddress (GetModuleHandle ("KERNEL32"), + "GetProcessInformation"); + MemoryBarrier (); + getprocessinfoinitialized = true; + } + /*#define ProcessMachineTypeInfo 9*/ + if (pGetProcessInformation && + pGetProcessInformation (process, (PROCESS_INFORMATION_CLASS)9, + &process_machine_info, sizeof (process_machine_info))) + process_arch = process_machine_info.ProcessMachine; + else + process_arch = native_arch; + } + else + { + is_wow = TRUE; + } + return TRUE; +} + +/** + * Terminates the process corresponding to the process ID + * + * This way of terminating the processes is not gentle: the process gets + * no chance of cleaning up after itself (closing file handles, removing + * .lock files, terminating spawned processes (if any), etc). + */ +static int +exit_process (HANDLE process, int exit_code) +{ + LPTHREAD_START_ROUTINE address = NULL; + DWORD pid = GetProcessId (process), code; + int signo = exit_code & 0x7f; + switch (signo) + { + case SIGINT: + case SIGQUIT: + /* We are not going to kill them but simply say that Ctrl+C + is pressed. If the processes want they can exit or else + just wait.*/ + if (kill_via_console_helper ( + process, L"CtrlRoutine", + signo == SIGINT ? CTRL_C_EVENT : CTRL_BREAK_EVENT, pid)) + return 0; + /* fall-through */ + case SIGTERM: + if (kill_via_console_helper (process, L"ExitProcess", exit_code, pid)) + return 0; + break; + default: + break; + } + + return int (TerminateProcess (process, exit_code)); +} + +#include +#include + +/** + * Terminates the process corresponding to the process ID and all of its + * directly and indirectly spawned subprocesses using the + * TerminateProcess() function. + */ +static int +exit_process_tree (HANDLE main_process, int exit_code) +{ + HANDLE snapshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); + PROCESSENTRY32 entry; + DWORD pids[16384]; + int max_len = sizeof (pids) / sizeof (*pids), i, len, ret = 0; + DWORD pid = GetProcessId (main_process); + int signo = exit_code & 0x7f; + + pids[0] = pid; + len = 1; + + /* + * Even if Process32First()/Process32Next() seem to traverse the + * processes in topological order (i.e. parent processes before + * child processes), there is nothing in the Win32 API documentation + * suggesting that this is guaranteed. + * + * Therefore, run through them at least twice and stop when no more + * process IDs were added to the list. + */ + for (;;) + { + memset (&entry, 0, sizeof (entry)); + entry.dwSize = sizeof (entry); + + if (!Process32First (snapshot, &entry)) + break; + + int orig_len = len; + do + { + /** + * Look for the parent process ID in the list of pids to kill, and if + * found, add it to the list. + */ + for (i = len - 1; i >= 0; i--) + { + if (pids[i] == entry.th32ProcessID) + break; + if (pids[i] != entry.th32ParentProcessID) + continue; + + /* We found a process to kill; is it an MSYS2 process? */ + pid_t cyg_pid = cygwin_winpid_to_pid (entry.th32ProcessID); + if (cyg_pid > -1) + { + if (cyg_pid == getpgid (cyg_pid)) + kill (cyg_pid, signo); + break; + } + pids[len++] = entry.th32ProcessID; + break; + } + } + while (len < max_len && Process32Next (snapshot, &entry)); + + if (orig_len == len || len >= max_len) + break; + } + + CloseHandle (snapshot); + + for (i = len - 1; i >= 0; i--) + { + HANDLE process; + + if (!i) + process = main_process; + else + { + process = OpenProcess ( + PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION + | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, + FALSE, pids[i]); + if (!process) + process = OpenProcess ( + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_TERMINATE, + FALSE, pids[i]); + } + DWORD code; + + if (process + && (!GetExitCodeProcess (process, &code) || code == STILL_ACTIVE)) + { + if (!exit_process (process, exit_code)) + ret = -1; + } + if (process && process != main_process) + CloseHandle (process); + } + + return ret; +} + +#endif From 86cd50d151515388c06d5f0e860cf002480d94fd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 20 Mar 2015 10:01:50 +0000 Subject: [PATCH 086/116] kill: kill Win32 processes more gently This change is the equivalent to the change to the Ctrl+C handling we just made. Co-authored-by: Naveen M K Signed-off-by: Johannes Schindelin --- winsup/utils/kill.cc | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/winsup/utils/kill.cc b/winsup/utils/kill.cc index bcabcd47c9..31ad57a137 100644 --- a/winsup/utils/kill.cc +++ b/winsup/utils/kill.cc @@ -17,6 +17,7 @@ details. */ #include #include #include +#include static char *prog_name; @@ -300,10 +301,20 @@ forcekill (pid_t pid, DWORD winpid, int sig, int wait) return; } if (!wait || WaitForSingleObject (h, 200) != WAIT_OBJECT_0) - if (sig && !TerminateProcess (h, sig << 8) - && WaitForSingleObject (h, 200) != WAIT_OBJECT_0) - fprintf (stderr, "%s: couldn't kill pid %u, %u\n", - prog_name, (unsigned int) dwpid, (unsigned int) GetLastError ()); + { + HANDLE cur = GetCurrentProcess (), h2; + /* duplicate handle with access rights required for exit_process_tree() */ + if (DuplicateHandle (cur, h, cur, &h2, PROCESS_CREATE_THREAD | + PROCESS_QUERY_INFORMATION | + PROCESS_VM_OPERATION | + PROCESS_VM_WRITE | PROCESS_VM_READ | + PROCESS_TERMINATE, FALSE, 0)) + { + CloseHandle(h); + h = h2; + } + exit_process_tree (h, 128 + sig); + } CloseHandle (h); } From 4b228ef2e491970f967aaed3339ce807c282d73c Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Thu, 22 Jul 2021 11:59:16 -0700 Subject: [PATCH 087/116] Cygwin: make option for native inner link handling. This code has been causing issues with SUBST and mapped network drives, so add an option (defaulted to on) which can be used to disable it where needed. MSYS=nonativeinnerlinks --- winsup/cygwin/environ.cc | 1 + winsup/cygwin/globals.cc | 1 + winsup/cygwin/path.cc | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index b9600ef9a8..06b1111f51 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -123,6 +123,7 @@ static struct parse_thing {"error_start", {func: error_start_init}, isfunc, NULL, {{0}, {0}}}, {"export", {&export_settings}, setbool, NULL, {{false}, {true}}}, {"glob", {func: glob_init}, isfunc, NULL, {{0}, {s: "normal"}}}, + {"nativeinnerlinks", {&nativeinnerlinks}, setbool, NULL, {{false}, {true}}}, {"pipe_byte", {&pipe_byte}, setbool, NULL, {{false}, {true}}}, {"proc_retry", {func: set_proc_retry}, isfunc, NULL, {{0}, {5}}}, {"reset_com", {&reset_com}, setbool, NULL, {{false}, {true}}}, diff --git a/winsup/cygwin/globals.cc b/winsup/cygwin/globals.cc index b3b77de405..ab2c205609 100644 --- a/winsup/cygwin/globals.cc +++ b/winsup/cygwin/globals.cc @@ -74,6 +74,7 @@ bool wincmdln = true; winsym_t allow_winsymlinks = WSYM_deepcopy; bool disable_pcon; bool winjitdebug = false; +bool nativeinnerlinks = true; /* Taken from BSD libc: This variable is zero until a process has created a pthread. It is used diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 39819dc694..b0c45fa55c 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -3722,7 +3722,8 @@ symlink_info::check (char *path, const suffix_info *suffixes, fs_info &fs, differ, return the final path as symlink content and set symlen to a negative value. This forces path_conv::check to restart symlink evaluation with the new path. */ - if ((pc_flags & (PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP)) == PC_SYM_FOLLOW) + if (nativeinnerlinks + && (pc_flags & (PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP)) == PC_SYM_FOLLOW) { PWCHAR fpbuf = tp.w_get (); DWORD ret; From 6e0c3b56c7c232ad7a20a2a93fd1679ca58e4a2c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2021 14:20:07 +0100 Subject: [PATCH 088/116] docs: skip building texinfo and PDF files The MSYS2 packages lack the infrastructure to build those. Signed-off-by: Johannes Schindelin --- winsup/configure.ac | 7 +++---- winsup/doc/Makefile.am | 9 +++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/winsup/configure.ac b/winsup/configure.ac index b9e3977fcf..b88f3ade29 100644 --- a/winsup/configure.ac +++ b/winsup/configure.ac @@ -84,11 +84,10 @@ AM_CONDITIONAL(BUILD_DOC, [test $enable_doc != "no"]) AC_CHECK_PROGS([DOCBOOK2XTEXI], [docbook2x-texi db2x_docbook2texi]) if test -z "$DOCBOOK2XTEXI" ; then if test "x$enable_doc" != "xno"; then - AC_MSG_ERROR([docbook2texi is required to build documentation]) - else - unset DOCBOOK2XTEXI - AM_MISSING_PROG([DOCBOOK2XTEXI], [docbook2texi]) + AC_MSG_WARN([docbook2texi is required to build documentation]) fi + unset DOCBOOK2XTEXI + AM_MISSING_PROG([DOCBOOK2XTEXI], [docbook2texi]) fi AC_CHECK_PROGS([XMLTO], [xmlto]) diff --git a/winsup/doc/Makefile.am b/winsup/doc/Makefile.am index 650e0c9247..55e9b95e78 100644 --- a/winsup/doc/Makefile.am +++ b/winsup/doc/Makefile.am @@ -10,9 +10,7 @@ man1_MANS = man3_MANS = man5_MANS = -doc_DATA = \ - cygwin-ug-net/cygwin-ug-net.pdf \ - cygwin-api/cygwin-api.pdf +doc_DATA = htmldir = $(datarootdir)/doc @@ -35,8 +33,7 @@ all-local: Makefile.dep \ cygwin-ug-net/cygwin-ug-net.html \ faq/faq.html faq/faq.body \ cygwin-ug-net/cygwin-ug-net-nochunks.html.gz \ - api2man.stamp intro2man.stamp utils2man.stamp \ - cygwin-api.info cygwin-ug-net.info + api2man.stamp intro2man.stamp utils2man.stamp clean-local: rm -f Makefile.dep @@ -76,7 +73,7 @@ install-etc: @$(MKDIR_P) $(DESTDIR)$(sysconfdir)/preremove $(INSTALL_SCRIPT) $(srcdir)/etc.preremove.cygwin-doc.sh $(DESTDIR)$(sysconfdir)/preremove/cygwin-doc.sh -install-data-hook: install-extra-man install-html-local install-info-local install-etc +install-data-hook: install-extra-man install-html-local install-etc uninstall-extra-man: for i in *.1 ; do \ From ecf50e64ce03f2840dc08605e087c2f3f361c14b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2021 16:22:57 +0100 Subject: [PATCH 089/116] install-libs: depend on the "toollibs" Before symlinking libg.a, we need the symlink source `libmsys-2.0.a`: in MSYS2, we copy by default (if we were creating Unix-style symlinks, the target would not have to exist before symlinking, but when copying we do need the source _right away_). Signed-off-by: Johannes Schindelin --- winsup/cygwin/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/Makefile.am b/winsup/cygwin/Makefile.am index b1b0df708e..1064b416b7 100644 --- a/winsup/cygwin/Makefile.am +++ b/winsup/cygwin/Makefile.am @@ -699,7 +699,7 @@ man_MANS = regex/regex.3 regex/regex.7 install-exec-hook: install-libs install-data-local: install-headers install-ldif -install-libs: +install-libs: install-toollibDATA @$(MKDIR_P) $(DESTDIR)$(bindir) $(INSTALL_PROGRAM) $(NEW_DLL_NAME) $(DESTDIR)$(bindir)/$(DLL_NAME) @$(MKDIR_P) $(DESTDIR)$(toollibdir) From 8cb4ff2c0ecb196f77686ada7f3c165b7183d380 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 23 Nov 2015 20:03:11 +0100 Subject: [PATCH 090/116] POSIX-ify the SHELL variable When calling a non-MSys2 binary, all of the environment is converted from POSIX to Win32, including the SHELL environment variable. In Git for Windows, for example, `SHELL=/usr/bin/bash` is converted to `SHELL=C:\Program Files\Git\usr\bin\bash.exe` when calling the `git.exe` binary. This is appropriate because non-MSys2 binaries would not handle POSIX paths correctly. Under certain circumstances, however, `git.exe` calls an *MSys2* binary in turn, such as `git config --edit` calling `vim.exe` unless Git is configured to use another editor specifically. Now, when this "improved vi" calls shell commands, it uses that $SHELL variable *without quoting*, resulting in a nasty error: C:\Program: No such file or directory Many other programs behave in the same manner, assuming that $SHELL does not contain spaces and hence needs no quoting, unfortunately including some of Git's own scripts. Therefore let's make sure that $SHELL gets "posified" again when entering MSys2 programs. Earlier attempts by Git for Windows contributors claimed that adding `SHELL` to the `conv_envvars` array does not have the intended effect. These reports just missed that the `conv_start_chars` array (which makes the code more performant) needs to be adjusted, too. Note that we set the `immediate` flag to `true` so that the environment variable is set immediately by the MSys2 runtime, i.e. not only spawned processes will see the POSIX-ified `SHELL` variable, but the MSys2 runtime *itself*, too. This fixes https://github.com/git-for-windows/git/issues/542, https://github.com/git-for-windows/git/issues/498, and https://github.com/git-for-windows/git/issues/468. Signed-off-by: Johannes Schindelin --- winsup/cygwin/environ.cc | 8 +++++++- winsup/cygwin/local_includes/environ.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 06b1111f51..e21c8fddb9 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -323,6 +323,7 @@ static win_env conv_envvars[] = {NL ("HOME="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, {NL ("LD_LIBRARY_PATH="), NULL, NULL, env_plist_to_posix, env_plist_to_win32, true}, + {NL ("SHELL="), NULL, NULL, env_path_to_posix, env_path_to_win32, true, true}, {NL ("TMPDIR="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, {NL ("TMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, {NL ("TEMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, @@ -351,7 +352,7 @@ static const unsigned char conv_start_chars[256] = WC, 0, 0, 0, WC, 0, 0, 0, /* 80 */ /* P Q R S T U V W */ - WC, 0, 0, 0, WC, 0, 0, 0, + WC, 0, 0, WC, WC, 0, 0, 0, /* 88 */ /* x Y Z */ 0, 0, 0, 0, 0, 0, 0, 0, @@ -380,6 +381,7 @@ win_env::operator = (struct win_env& x) toposix = x.toposix; towin32 = x.towin32; immediate = false; + skip_if_empty = x.skip_if_empty; return *this; } @@ -401,6 +403,8 @@ win_env::add_cache (const char *in_posix, const char *in_native) native = (char *) realloc (native, namelen + 1 + strlen (in_native)); stpcpy (stpcpy (native, name), in_native); } + else if (skip_if_empty && !*in_posix) + native = (char *) calloc(1, 1); else { tmp_pathbuf tp; @@ -466,6 +470,8 @@ posify_maybe (char **here, const char *value, char *outenv) return; int len = strcspn (src, "=") + 1; + if (conv->skip_if_empty && !src[len]) + return; /* Turn all the items from c:; into their mounted equivalents - if there is one. */ diff --git a/winsup/cygwin/local_includes/environ.h b/winsup/cygwin/local_includes/environ.h index 0dd45359cc..fd6ca466e8 100644 --- a/winsup/cygwin/local_includes/environ.h +++ b/winsup/cygwin/local_includes/environ.h @@ -21,7 +21,7 @@ struct win_env char *native; ssize_t (*toposix) (const void *, void *, size_t); ssize_t (*towin32) (const void *, void *, size_t); - bool immediate; + bool immediate, skip_if_empty; void add_cache (const char *in_posix, const char *in_native = NULL); const char * get_native () const {return native ? native + namelen : NULL;} const char * get_posix () const {return posix ? posix : NULL;} From 1f6020c6bfa115ac641881aadeece5ee40eb02bc Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 21 Mar 2017 13:18:38 +0100 Subject: [PATCH 091/116] Handle ORIGINAL_PATH just like PATH MSYS2 recently introduced that hack where the ORIGINAL_PATH variable is set to the original PATH value in /etc/profile, unless previously set. In Git for Windows' default mode, that ORIGINAL_PATH value is the used to define the PATH variable explicitly. So far so good. The problem: when calling from inside an MSYS2 process (such as Bash) a MINGW executable (such as git.exe) that then calls another MSYS2 executable (such as bash.exe), that latter call will try to re-convert ORIGINAL_PATH after the previous call converted ORIGINAL_PATH from POSIX to Windows paths. And this conversion may very well fail, e.g. when the path list contains mixed semicolons and colons. So let's just *force* the MSYS2 runtime to handle ORIGINAL_PATH in the same way as the PATH variable (which conversion works, as we know). Signed-off-by: Johannes Schindelin --- winsup/cygwin/environ.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index e21c8fddb9..031db039ea 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -323,6 +323,7 @@ static win_env conv_envvars[] = {NL ("HOME="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, {NL ("LD_LIBRARY_PATH="), NULL, NULL, env_plist_to_posix, env_plist_to_win32, true}, + {NL ("ORIGINAL_PATH="), NULL, NULL, env_PATH_to_posix, env_plist_to_win32, true}, {NL ("SHELL="), NULL, NULL, env_path_to_posix, env_path_to_win32, true, true}, {NL ("TMPDIR="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, {NL ("TMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, @@ -349,7 +350,7 @@ static const unsigned char conv_start_chars[256] = 0, 0, 0, 0, 0, 0, 0, 0, /* 72 */ /* H I J K L M N O */ - WC, 0, 0, 0, WC, 0, 0, 0, + WC, 0, 0, 0, WC, 0, 0, WC, /* 80 */ /* P Q R S T U V W */ WC, 0, 0, WC, WC, 0, 0, 0, From 79e3880244c30efecd2221a0bc90d452a62d873e Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Sun, 3 Jul 2022 22:39:32 +0200 Subject: [PATCH 092/116] uname: allow setting the system name to CYGWIN We are currently trying to move our cygwin build environment closer to cygwin and some autotools/bash based build systems call "uname -s" to figure out the OS and in many cases only handle the cygwin case, so we have to patch them. With this instead of patching we can set MSYSTEM=CYGWIN and change uname output that way. The next step would be to always output CYGWIN in an msys env by default, but for now this allows us to get rid of all the patches without affecting users. --- winsup/cygwin/uname.cc | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/winsup/cygwin/uname.cc b/winsup/cygwin/uname.cc index 0d0c5aa52a..a4ac0e304d 100644 --- a/winsup/cygwin/uname.cc +++ b/winsup/cygwin/uname.cc @@ -24,6 +24,24 @@ extern "C" int getdomainname (char *__name, size_t __len); #define ATTRIBUTE_NONSTRING #endif +static const char* +get_sysname() +{ +#ifdef __MSYS__ + char* msystem = getenv("MSYSTEM"); + if (!msystem || strcmp(msystem, "MSYS") == 0) + return "MSYS"; + else if (strcmp(msystem, "CYGWIN") == 0) + return "CYGWIN"; + else if (strstr(msystem, "32") != NULL) + return "MINGW32"; + else + return "MINGW64"; +#else + return "CYGWIN"; +#endif +} + /* uname: POSIX 4.4.1.1 */ /* New entrypoint for applications since API 335 */ @@ -36,12 +54,9 @@ uname_x (struct utsname *name) memset (name, 0, sizeof (*name)); /* sysname */ - char* msystem = getenv("MSYSTEM"); - const char* msystem_sysname = "MSYS"; - if (msystem != NULL && *msystem && strcmp(msystem, "MSYS") != 0) - msystem_sysname = (strstr(msystem, "32") != NULL) ? "MINGW32" : "MINGW64";; + const char* sysname = get_sysname(); __small_sprintf (name->sysname, "%s_%s-%u", - msystem_sysname, + sysname, wincap.osname (), wincap.build_number ()); /* nodename */ memset (buf, 0, sizeof buf); @@ -107,15 +122,8 @@ uname (struct utsname *in_name) __try { memset (name, 0, sizeof (*name)); -#ifdef __MSYS__ - char* msystem = getenv("MSYSTEM"); - const char* msystem_sysname = "MSYS"; - if (msystem != NULL && *msystem && strcmp(msystem, "MSYS") != 0) - msystem_sysname = (strstr(msystem, "32") != NULL) ? "MINGW32" : "MINGW64"; - __small_sprintf (name->sysname, "%s_%s", msystem_sysname, wincap.osname ()); -#else - __small_sprintf (name->sysname, "CYGWIN_%s", wincap.osname ()); -#endif + const char* sysname = get_sysname(); + __small_sprintf (name->sysname, "%s_%s", sysname, wincap.osname ()); /* Computer name */ cygwin_gethostname (name->nodename, sizeof (name->nodename) - 1); From ef59c45434b5296d18f7aab785ca2db13f1be8d7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 18 Feb 2015 12:32:17 +0000 Subject: [PATCH 093/116] Pass environment variables with empty values There is a difference between an empty value and an unset environment variable. We should not confuse both; If the user wants to unset an environment variable, they can certainly do so (unsetenv(3), or in the shell: 'unset ABC'). This fixes Git's t3301-notes.sh, which overrides environment variables with empty values. Signed-off-by: Johannes Schindelin --- winsup/cygwin/environ.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 031db039ea..6b385cd03d 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -1326,11 +1326,11 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, Note that this doesn't stop invalid strings without '=' in it etc., but we're opting for speed here for now. Adding complete checking would be pretty expensive. */ - if (len == 1 || !*rest) + if (len == 1) continue; /* See if this entry requires posix->win32 conversion. */ - conv = getwinenv (*srcp, rest, &temp); + conv = !*rest ? NULL : getwinenv (*srcp, rest, &temp); if (conv) { p = conv->native; /* Use win32 path */ @@ -1344,7 +1344,7 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, } } #ifdef __MSYS__ - else if (!keep_posix) { + else if (!keep_posix && *rest) { char *win_arg = arg_heuristic_with_exclusions (*srcp, msys2_env_conv_excl_env, msys2_env_conv_excl_count); debug_printf("WIN32_PATH is %s", win_arg); From c347d6c26b4722c12051ef0d19257323dafbd75b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 6 Sep 2022 10:40:58 +0200 Subject: [PATCH 094/116] Optionally disallow empty environment values again We just disabled the code that skips environment variables whose values are empty. However, this code was introduced a long time ago into Cygwin in d6b1ac7faa (* environ.cc (build_env): Don't put an empty environment variable into the environment. Optimize use of "len". * errno.cc (ERROR_MORE_DATA): Translate to EMSGSIZE rather than EAGAIN., 2006-09-07), seemingly without any complaints. Meaning: There might very well be use cases out there where it makes sense to skip empty-valued environment variables. Therefore, it seems like a good idea to have a "knob" to turn it back on. With this commit, we introduce such a knob: by setting `noemptyenvvalues` the `MSYS` variable (or appending it if that variable is already set), users can tell the MSYS2 runtime to behave just like in the olden times. Signed-off-by: Johannes Schindelin --- winsup/cygwin/environ.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 6b385cd03d..12b4d57563 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -36,6 +36,7 @@ static char **lastenviron; /* Parse CYGWIN options */ static NO_COPY bool export_settings = false; +static bool emptyenvvalues = true; enum settings { @@ -119,6 +120,7 @@ static struct parse_thing } known[] NO_COPY = { {"disable_pcon", {&disable_pcon}, setbool, NULL, {{false}, {true}}}, + {"emptyenvvalues", {&emptyenvvalues}, setbool, NULL, {{false}, {true}}}, {"enable_pcon", {&disable_pcon}, setnegbool, NULL, {{true}, {false}}}, {"error_start", {func: error_start_init}, isfunc, NULL, {{0}, {0}}}, {"export", {&export_settings}, setbool, NULL, {{false}, {true}}}, @@ -1326,7 +1328,7 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, Note that this doesn't stop invalid strings without '=' in it etc., but we're opting for speed here for now. Adding complete checking would be pretty expensive. */ - if (len == 1) + if (len == 1 || (!emptyenvvalues && !*rest)) continue; /* See if this entry requires posix->win32 conversion. */ From 210e5f3c4d43efc6f6aa140cb28f3cbaf261593d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 6 Sep 2022 12:18:18 +0200 Subject: [PATCH 095/116] build_env(): respect the `MSYS` environment variable With this commit, you can call MSYS=noemptyenvvalues my-command and it does what is expected: to pass no empty-valued environment variables to `my-command`. Signed-off-by: Johannes Schindelin --- winsup/cygwin/environ.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 12b4d57563..4e049211e9 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -1204,7 +1204,11 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, { bool calc_tl = !no_envblock; #ifdef __MSYS__ - if (!keep_posix) + if (ascii_strncasematch(*srcp, "MSYS=", 5)) + { + parse_options (*srcp + 5); + } + else if (!keep_posix) { /* Don't pass timezone environment to non-msys applications */ if (ascii_strncasematch(*srcp, "TZ=", 3)) From bef1e6ba82fb0a7992caeee892721fe4214b64ab Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Sat, 17 Dec 2022 20:14:49 +0100 Subject: [PATCH 096/116] Revert "Cygwin: Enable dynamicbase on the Cygwin DLL by default" This reverts commit 943433b00cacdde0cb9507d0178770a2fb67bd71. This seems to fix fork errors under Docker, see https://cygwin.com/pipermail/cygwin/2022-December/252711.html --- winsup/cygwin/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/winsup/cygwin/Makefile.am b/winsup/cygwin/Makefile.am index 1064b416b7..76b54eba4f 100644 --- a/winsup/cygwin/Makefile.am +++ b/winsup/cygwin/Makefile.am @@ -600,8 +600,7 @@ $(NEW_DLL_NAME): $(LDSCRIPT) libdll.a $(VERSION_OFILES) $(LIBSERVER)\ $(newlib_build)/libm.a $(newlib_build)/libc.a $(AM_V_CXXLD)$(CXX) $(CXXFLAGS) \ -mno-use-libstdc-wrappers \ - -Wl,--gc-sections -nostdlib -Wl,-T$(LDSCRIPT) \ - -Wl,--dynamicbase -static \ + -Wl,--gc-sections -nostdlib -Wl,-T$(LDSCRIPT) -static \ $${SOURCE_DATE_EPOCH:+-Wl,--no-insert-timestamp} \ -Wl,--heap=0 -Wl,--out-implib,msysdll.a -shared -o $@ \ -e @DLL_ENTRY@ $(DEF_FILE) \ From 8103a099cfaac55a8e2954c7636001c535ce48d7 Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Fri, 17 May 2024 19:37:45 +0200 Subject: [PATCH 097/116] CI: set -Wno-error=maybe-uninitialized After the update of msys2-w32api from v11.0.1 to current master (and soon to be v12) we get: winsup/cygwin/exceptions.cc:1736:33: error: '' may be used uninitialized [-Werror=maybe-uninitialized] Ignore it like the rest. Fixes #214 --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 5e11108335..57ee6639f5 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -22,7 +22,7 @@ jobs: run: | # XXX: cygwin still uses gcc v11 so we get new warnings with v13, # resulting in errors due to -Werror. Disable them for now. - export CXXFLAGS="-Wno-error=stringop-truncation -Wno-error=array-bounds -Wno-error=overloaded-virtual -Wno-narrowing -Wno-use-after-free" + export CXXFLAGS="-Wno-error=stringop-truncation -Wno-error=array-bounds -Wno-error=overloaded-virtual -Wno-narrowing -Wno-use-after-free -Wno-error=maybe-uninitialized" (cd winsup && ./autogen.sh) ./configure --disable-dependency-tracking make -j8 From 6e10b1bdd96863136dd3c0e1e71b9c7895def917 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 30 Jan 2023 23:22:22 +0100 Subject: [PATCH 098/116] Avoid sharing cygheaps across Cygwin versions It frequently leads to problems when trying, say, to call from MSYS2's Bash into Cygwin's or Git for Windows', merely because sharing that data is pretty finicky. For example, using the MSYS2' Bash using the MSYS2 runtime version that is current at time of writing, trying to call Cygwin's programs fails in manners like this: $ /c/cygwin64/bin/uname -r 0 [main] uname (9540) child_copy: cygheap read copy failed, 0x800000000..0x800010BE0, done 0, windows pid 9540, Win32 error 6 680 [main] uname 880 C:\cygwin64\bin\uname.exe: *** fatal error - couldn't create signal pipe, Win32 error 5 with the rather misleading exit code 127 (a code which is reserved to indicate that a command was not found). Let's just treat the MSYS2 runtime and the Cygwin runtime as completely incompatible with one another, by virtue of using a different magic constant than merely `CHILD_INFO_MAGIC`. By using the msys2-runtime commit to modify that magic constant, we can even spawn programs using a different MSYS2 runtime (such as Git for Windows') because the commit serves as the tell-tale whether two MSYS2 runtime versions are compatible with each other. To support building in the MSYS2-packages repository (where we do not check out the `msys2-runtime` but instead check out Cygwin and apply patches on top), let's accept a hard-coded commit hash as `./configure` option. One consequence is that spawned MSYS processes using a different MSYS2 runtime will not be visible as such to the parent process, i.e. they cannot share any resources such as pseudo terminals. But that's okay, they are simply treated as if they were regular Win32 programs. Note: We have to use a very rare form of encoding the brackets in the `expr` calls: quadrigraphs (for a thorough explanation, see https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.70/html_node/Quadrigraphs.html#Quadrigraphs). This is necessary because it is apparently impossible to encode brackets in `configure.ac` files otherwise. Signed-off-by: Johannes Schindelin --- winsup/configure.ac | 28 ++++++++++++++++++++++++++++ winsup/cygwin/Makefile.am | 3 +++ winsup/cygwin/dcrt0.cc | 2 +- winsup/cygwin/sigproc.cc | 2 +- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/winsup/configure.ac b/winsup/configure.ac index b88f3ade29..eb9890acec 100644 --- a/winsup/configure.ac +++ b/winsup/configure.ac @@ -57,6 +57,34 @@ AC_CHECK_TOOL(RANLIB, ranlib, ranlib) AC_CHECK_TOOL(STRIP, strip, strip) AC_CHECK_TOOL(WINDRES, windres, windres) +# Record msys2-runtime commit +AC_ARG_WITH([msys2-runtime-commit], + [AS_HELP_STRING([--with-msys2-runtime-commit=COMMIT], + [indicate the msys2-runtime commit corresponding to this build])], + [MSYS2_RUNTIME_COMMIT=$withval], [MSYS2_RUNTIME_COMMIT=yes]) +case "$MSYS2_RUNTIME_COMMIT" in +no) + MSYS2_RUNTIME_COMMIT= + MSYS2_RUNTIME_COMMIT_HEX=0 + ;; +yes|auto) + if MSYS2_RUNTIME_COMMIT="$(git --git-dir="$srcdir/../.git" rev-parse HEAD)" + then + MSYS2_RUNTIME_COMMIT_HEX="0x$(expr "$MSYS2_RUNTIME_COMMIT" : '\(.\{,8\}\)')ull" + else + AC_MSG_WARN([Could not determine msys2-runtime commit"]) + MSYS2_RUNTIME_COMMIT= + MSYS2_RUNTIME_COMMIT_HEX=0 + fi + ;; +*) + expr "$MSYS2_RUNTIME_COMMIT" : '@<:@0-9a-f@:>@\{6,64\}$' || + AC_MSG_ERROR([Invalid commit name: "$MSYS2_RUNTIME_COMMIT"]) + MSYS2_RUNTIME_COMMIT_HEX="0x$(expr "$MSYS2_RUNTIME_COMMIT" : '\(.\{,8\}\)')ull" + ;; +esac +AC_SUBST(MSYS2_RUNTIME_COMMIT_HEX) + AC_ARG_ENABLE(debugging, [AS_HELP_STRING([--enable-debugging],[Build a cygwin DLL which has more consistency checking for debugging])], [case "${enableval}" in diff --git a/winsup/cygwin/Makefile.am b/winsup/cygwin/Makefile.am index 76b54eba4f..774e562f51 100644 --- a/winsup/cygwin/Makefile.am +++ b/winsup/cygwin/Makefile.am @@ -17,6 +17,9 @@ if TARGET_X86_64 COMMON_CFLAGS+=-mcmodel=small endif +VERSION_CFLAGS = -DMSYS2_RUNTIME_COMMIT_HEX="@MSYS2_RUNTIME_COMMIT_HEX@" +COMMON_CFLAGS += $(VERSION_CFLAGS) + AM_CFLAGS=$(cflags_common) $(COMMON_CFLAGS) AM_CXXFLAGS=$(cxxflags_common) $(COMMON_CFLAGS) -fno-threadsafe-statics diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 0a5c817b3c..351d32d8e3 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -531,7 +531,7 @@ get_cygwin_startup_info () child_info *res = (child_info *) si.lpReserved2; if (si.cbReserved2 < EXEC_MAGIC_SIZE || !res - || res->intro != PROC_MAGIC_GENERIC || res->magic != CHILD_INFO_MAGIC) + || res->intro != PROC_MAGIC_GENERIC || res->magic != (CHILD_INFO_MAGIC ^ MSYS2_RUNTIME_COMMIT_HEX)) { strace.activate (false); res = NULL; diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 58a9e5a312..cf43aa9335 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -836,7 +836,7 @@ int child_info::retry_count = 0; child_info::child_info (unsigned in_cb, child_info_types chtype, bool need_subproc_ready): msv_count (0), cb (in_cb), intro (PROC_MAGIC_GENERIC), - magic (CHILD_INFO_MAGIC), type (chtype), cygheap (::cygheap), + magic (CHILD_INFO_MAGIC ^ MSYS2_RUNTIME_COMMIT_HEX), type (chtype), cygheap (::cygheap), cygheap_max (::cygheap_max), flag (0), retry (child_info::retry_count), rd_proc_pipe (NULL), wr_proc_pipe (NULL), sigmask (_my_tls.sigmask) { From f61f7fb71aaa15a8d6ccfc1b08dfca83b4118458 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 21 Feb 2023 16:36:36 +0100 Subject: [PATCH 099/116] uname: report msys2-runtime commit hash, too Having just Cygwin's version in the output of `uname` is not helpful, as both MSYS2 as well as Git for Windows release intermediate versions of the MSYS2 runtime much more often than Cygwin runtime versions are released. Signed-off-by: Johannes Schindelin --- winsup/configure.ac | 10 ++++++++-- winsup/cygwin/Makefile.am | 6 ++++-- winsup/cygwin/scripts/mkvers.sh | 8 ++++++++ winsup/cygwin/uname.cc | 16 +++++++++------- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/winsup/configure.ac b/winsup/configure.ac index eb9890acec..0fc607aad5 100644 --- a/winsup/configure.ac +++ b/winsup/configure.ac @@ -65,24 +65,30 @@ AC_ARG_WITH([msys2-runtime-commit], case "$MSYS2_RUNTIME_COMMIT" in no) MSYS2_RUNTIME_COMMIT= + MSYS2_RUNTIME_COMMIT_SHORT= MSYS2_RUNTIME_COMMIT_HEX=0 ;; yes|auto) if MSYS2_RUNTIME_COMMIT="$(git --git-dir="$srcdir/../.git" rev-parse HEAD)" then - MSYS2_RUNTIME_COMMIT_HEX="0x$(expr "$MSYS2_RUNTIME_COMMIT" : '\(.\{,8\}\)')ull" + MSYS2_RUNTIME_COMMIT_SHORT="$(expr "$MSYS2_RUNTIME_COMMIT" : '\(.\{,8\}\)')" + MSYS2_RUNTIME_COMMIT_HEX="0x${MSYS2_RUNTIME_COMMIT_SHORT}ul" else AC_MSG_WARN([Could not determine msys2-runtime commit"]) MSYS2_RUNTIME_COMMIT= + MSYS2_RUNTIME_COMMIT_SHORT= MSYS2_RUNTIME_COMMIT_HEX=0 fi ;; *) expr "$MSYS2_RUNTIME_COMMIT" : '@<:@0-9a-f@:>@\{6,64\}$' || AC_MSG_ERROR([Invalid commit name: "$MSYS2_RUNTIME_COMMIT"]) - MSYS2_RUNTIME_COMMIT_HEX="0x$(expr "$MSYS2_RUNTIME_COMMIT" : '\(.\{,8\}\)')ull" + MSYS2_RUNTIME_COMMIT_SHORT="$(expr "$MSYS2_RUNTIME_COMMIT" : '\(.\{,8\}\)')" + MSYS2_RUNTIME_COMMIT_HEX="0x${MSYS2_RUNTIME_COMMIT_SHORT}ul" ;; esac +AC_SUBST(MSYS2_RUNTIME_COMMIT) +AC_SUBST(MSYS2_RUNTIME_COMMIT_SHORT) AC_SUBST(MSYS2_RUNTIME_COMMIT_HEX) AC_ARG_ENABLE(debugging, diff --git a/winsup/cygwin/Makefile.am b/winsup/cygwin/Makefile.am index 774e562f51..abcb32360d 100644 --- a/winsup/cygwin/Makefile.am +++ b/winsup/cygwin/Makefile.am @@ -17,7 +17,9 @@ if TARGET_X86_64 COMMON_CFLAGS+=-mcmodel=small endif -VERSION_CFLAGS = -DMSYS2_RUNTIME_COMMIT_HEX="@MSYS2_RUNTIME_COMMIT_HEX@" +VERSION_CFLAGS = -DMSYS2_RUNTIME_COMMIT="\"@MSYS2_RUNTIME_COMMIT@\"" +VERSION_CFLAGS += -DMSYS2_RUNTIME_COMMIT_SHORT="\"@MSYS2_RUNTIME_COMMIT_SHORT@\"" +VERSION_CFLAGS += -DMSYS2_RUNTIME_COMMIT_HEX="@MSYS2_RUNTIME_COMMIT_HEX@" COMMON_CFLAGS += $(VERSION_CFLAGS) AM_CFLAGS=$(cflags_common) $(COMMON_CFLAGS) @@ -452,7 +454,7 @@ uname_version.c: .FORCE version.cc: scripts/mkvers.sh include/cygwin/version.h winver.rc $(src_files) @echo "Making version.cc and winver.o";\ export CC="$(CC)";\ - /bin/sh $(word 1,$^) $(word 2,$^) $(word 3,$^) $(WINDRES) $(CFLAGS) + /bin/sh $(word 1,$^) $(word 2,$^) $(word 3,$^) $(WINDRES) $(CFLAGS) $(VERSION_CFLAGS) winver.o: version.cc diff --git a/winsup/cygwin/scripts/mkvers.sh b/winsup/cygwin/scripts/mkvers.sh index a3d45c5db0..34d8d6dce1 100755 --- a/winsup/cygwin/scripts/mkvers.sh +++ b/winsup/cygwin/scripts/mkvers.sh @@ -16,6 +16,7 @@ incfile="$1"; shift rcfile="$1"; shift windres="$1"; shift iflags= +msys2_runtime_commit= # Find header file locations while [ -n "$*" ]; do case "$1" in @@ -26,6 +27,9 @@ while [ -n "$*" ]; do shift iflags="$iflags -I$1" ;; + -DMSYS2_RUNTIME_COMMIT=*) + msys2_runtime_commit="${1#*=}" + ;; esac shift done @@ -168,6 +172,10 @@ then cvs_tag="$(echo $wv_cvs_tag | sed -e 's/-branch.*//')" cygwin_ver="$cygwin_ver-$cvs_tag" fi +if [ -n "$msys2_runtime_commit" ] +then + cygwin_ver="$cygwin_ver-$msys2_runtime_commit" +fi echo "Version $cygwin_ver" set -$- $builddate diff --git a/winsup/cygwin/uname.cc b/winsup/cygwin/uname.cc index a4ac0e304d..a978363f1c 100644 --- a/winsup/cygwin/uname.cc +++ b/winsup/cygwin/uname.cc @@ -76,18 +76,19 @@ uname_x (struct utsname *name) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-truncation=" #ifdef CYGPORT_RELEASE_INFO - snprintf (name->release, _UTSNAME_LENGTH, "%s.%s", - __XSTRING (CYGPORT_RELEASE_INFO), name->machine); + snprintf (name->release, _UTSNAME_LENGTH, "%s-%s.%s", + __XSTRING (CYGPORT_RELEASE_INFO), MSYS2_RUNTIME_COMMIT_SHORT, name->machine); #else extern const char *uname_dev_version; if (uname_dev_version && uname_dev_version[0]) - snprintf (name->release, _UTSNAME_LENGTH, "%s.%s", - uname_dev_version, name->machine); + snprintf (name->release, _UTSNAME_LENGTH, "%s-%s.%s", + uname_dev_version, MSYS2_RUNTIME_COMMIT_SHORT, name->machine); else - __small_sprintf (name->release, "%d.%d.%d-api-%d.%s", + __small_sprintf (name->release, "%d.%d.%d-%s-api-%d.%s", cygwin_version.dll_major / 1000, cygwin_version.dll_major % 1000, cygwin_version.dll_minor, + MSYS2_RUNTIME_COMMIT_SHORT, cygwin_version.api_minor, name->machine); #endif @@ -129,14 +130,15 @@ uname (struct utsname *in_name) cygwin_gethostname (name->nodename, sizeof (name->nodename) - 1); /* Cygwin dll release */ - __small_sprintf (name->release, "%d.%d.%d(%d.%d/%d/%d)", + __small_sprintf (name->release, "%d.%d.%d(%d.%d/%d/%d/%s)", cygwin_version.dll_major / 1000, cygwin_version.dll_major % 1000, cygwin_version.dll_minor, cygwin_version.api_major, cygwin_version.api_minor, cygwin_version.shared_data, - cygwin_version.mount_registry); + cygwin_version.mount_registry, + MSYS2_RUNTIME_COMMIT_SHORT); /* Cygwin "version" aka build date */ strcpy (name->version, cygwin_version.dll_build_date); From debafbf93f8c7099eb9147d40db596af221fed19 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Tue, 13 Feb 2024 16:47:51 +0100 Subject: [PATCH 100/116] Cygwin: find_fast_cwd: don't run assembler checking code on ARM64 https://cygwin.com/pipermail/cygwin/2024-February/255397.html reports a crash on ARM64 probably related to checking x86_64 code on the x86_64 emulator on AArch64. At least for testing, pull the code checking the host HW up to be called before trying to evaluate assembler code. This fixes https://github.com/git-for-windows/git/issues/4808 Backported from 4e77fa9b8b (Cygwin: find_fast_cwd: don't run assembler checking code on ARM64, 2024-02-13). Signed-off-by: Corinna Vinschen Signed-off-by: Johannes Schindelin --- winsup/cygwin/path.cc | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index b0c45fa55c..f8afd4c594 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -4826,29 +4826,27 @@ find_fast_cwd_pointer () static fcwd_access_t ** find_fast_cwd () { + USHORT emulated, hosted; + fcwd_access_t **f_cwd_ptr; + + /* First check if we're running in WOW64 on ARM64 emulating AMD64. Skip + fetching FAST_CWD pointer as long as there's no solution for finding + it on that system. */ + if (IsWow64Process2 (GetCurrentProcess (), &emulated, &hosted) + && hosted == IMAGE_FILE_MACHINE_ARM64) + return NULL; + /* Fetch the pointer but don't set the global fast_cwd_ptr yet. First we have to make sure we know the version of the FAST_CWD structure used on the system. */ - fcwd_access_t **f_cwd_ptr = find_fast_cwd_pointer (); + f_cwd_ptr = find_fast_cwd_pointer (); if (!f_cwd_ptr) - { - bool warn = 1; - USHORT emulated, hosted; - - /* Check if we're running in WOW64 on ARM64 emulating AMD64. Skip - warning as long as there's no solution for finding the FAST_CWD - pointer on that system. */ - if (IsWow64Process2 (GetCurrentProcess (), &emulated, &hosted) - && hosted == IMAGE_FILE_MACHINE_ARM64) - warn = 0; - - if (warn) - small_printf ("Cygwin WARNING:\n" + small_printf ("Cygwin WARNING:\n" " Couldn't compute FAST_CWD pointer. This typically occurs if you're using\n" " an older Cygwin version on a newer Windows. Please update to the latest\n" " available Cygwin version from https://cygwin.com/. If the problem persists,\n" " please see https://cygwin.com/problems.html\n\n"); - } + /* Eventually, after we set the version as well, set fast_cwd_ptr. */ return f_cwd_ptr; } From 2c55ca50eeb8532432f51391c2ec28a14fc4e510 Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Mon, 11 Nov 2024 20:09:49 -0800 Subject: [PATCH 101/116] cygthread: suspend thread before terminating. This addresses an extremely difficult to debug deadlock when running under emulation on ARM64. A relatively easy way to trigger this bug is to call `fork()`, then within the child process immediately call another `fork()` and then `exit()` the intermediate process. It would seem that there is a "code emulation" lock on the wait thread at this stage, and if the thread is terminated too early, that lock still exists albeit without a thread, and nothing moves forward. It seems that a `SuspendThread()` combined with a `GetThreadContext()` (to force the thread to _actually_ be suspended, for more details see https://devblogs.microsoft.com/oldnewthing/20150205-00/?p=44743) makes sure the thread is "booted" from emulation before it is suspended. Hopefully this means it won't be holding any locks or otherwise leave emulation in a bad state when the thread is terminated. Also, attempt to use `CancelSynchonousIo()` (as seen in `flock.cc`) to avoid the need for `TerminateThread()` altogether. This doesn't always work, however, so was not a complete fix for the deadlock issue. Addresses: https://cygwin.com/pipermail/cygwin-developers/2024-May/012694.html Signed-off-by: Jeremy Drake --- winsup/cygwin/cygthread.cc | 14 ++++++++++++++ winsup/cygwin/pinfo.cc | 10 +++++++--- winsup/cygwin/sigproc.cc | 12 ++++++++++-- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/winsup/cygwin/cygthread.cc b/winsup/cygwin/cygthread.cc index 54918e7677..4f16097531 100644 --- a/winsup/cygwin/cygthread.cc +++ b/winsup/cygwin/cygthread.cc @@ -302,6 +302,20 @@ cygthread::terminate_thread () if (!inuse) goto force_notterminated; + if (_my_tls._ctinfo != this) + { + CONTEXT context; + context.ContextFlags = CONTEXT_CONTROL; + /* SuspendThread makes sure a thread is "booted" from emulation before + it is suspended. As such, the emulator hopefully won't be in a bad + state (aka, holding any locks) when the thread is terminated. */ + SuspendThread (h); + /* We need to call GetThreadContext, even though we don't care about the + context, because SuspendThread is asynchronous and GetThreadContext + will make sure the thread is *really* suspended before returning */ + GetThreadContext (h, &context); + } + TerminateThread (h, 0); WaitForSingleObject (h, INFINITE); CloseHandle (h); diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc index a5f5d6eb22..4bb19464b4 100644 --- a/winsup/cygwin/pinfo.cc +++ b/winsup/cygwin/pinfo.cc @@ -1262,13 +1262,17 @@ proc_waiter (void *arg) for (;;) { - DWORD nb; + DWORD nb, err; char buf = '\0'; if (!ReadFile (vchild.rd_proc_pipe, &buf, 1, &nb, NULL) - && GetLastError () != ERROR_BROKEN_PIPE) + && (err = GetLastError ()) != ERROR_BROKEN_PIPE) { - system_printf ("error on read of child wait pipe %p, %E", vchild.rd_proc_pipe); + /* ERROR_OPERATION_ABORTED is expected due to the possibility that + CancelSynchronousIo interruped the ReadFile call, so don't output + that error */ + if (err != ERROR_OPERATION_ABORTED) + system_printf ("error on read of child wait pipe %p, %E", vchild.rd_proc_pipe); break; } diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index cf43aa9335..4260f8807e 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -413,7 +413,11 @@ proc_terminate () to 1 iff it is a Cygwin process. */ if (!have_execed || !have_execed_cygwin) chld_procs[i]->ppid = 1; - if (chld_procs[i].wait_thread) + /* Attempt to exit the wait_thread cleanly via CancelSynchronousIo + before falling back to the (explicitly dangerous) cross-thread + termination */ + if (chld_procs[i].wait_thread + && !CancelSynchronousIo (chld_procs[i].wait_thread->thread_handle ())) chld_procs[i].wait_thread->terminate_thread (); /* Release memory associated with this process unless it is 'myself'. 'myself' is only in the chld_procs table when we've execed. We @@ -1199,7 +1203,11 @@ remove_proc (int ci) { if (have_execed) { - if (_my_tls._ctinfo != chld_procs[ci].wait_thread) + /* Attempt to exit the wait_thread cleanly via CancelSynchronousIo + before falling back to the (explicitly dangerous) cross-thread + termination */ + if (_my_tls._ctinfo != chld_procs[ci].wait_thread + && !CancelSynchronousIo (chld_procs[ci].wait_thread->thread_handle ())) chld_procs[ci].wait_thread->terminate_thread (); } else if (chld_procs[ci] && chld_procs[ci]->exists ()) From e5dc132b3fa1c6a06867e73c7f67c81a502e3993 Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Thu, 21 Nov 2024 22:13:42 -0800 Subject: [PATCH 102/116] Cygwin: revert use of CancelSyncronousIo on wait_thread. It appears this is causing hangs on native x86_64 in similar scenarios as the hangs on ARM64, because `CancelSynchronousIo` is returning `TRUE` but not canceling the `ReadFile` call as expected. Addresses: https://github.com/msys2/MSYS2-packages/issues/4340#issuecomment-2491401847 Fixes: b091b47b9e56 ("cygthread: suspend thread before terminating.") Signed-off-by: Jeremy Drake --- winsup/cygwin/pinfo.cc | 10 +++------- winsup/cygwin/sigproc.cc | 12 ++---------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc index 4bb19464b4..a5f5d6eb22 100644 --- a/winsup/cygwin/pinfo.cc +++ b/winsup/cygwin/pinfo.cc @@ -1262,17 +1262,13 @@ proc_waiter (void *arg) for (;;) { - DWORD nb, err; + DWORD nb; char buf = '\0'; if (!ReadFile (vchild.rd_proc_pipe, &buf, 1, &nb, NULL) - && (err = GetLastError ()) != ERROR_BROKEN_PIPE) + && GetLastError () != ERROR_BROKEN_PIPE) { - /* ERROR_OPERATION_ABORTED is expected due to the possibility that - CancelSynchronousIo interruped the ReadFile call, so don't output - that error */ - if (err != ERROR_OPERATION_ABORTED) - system_printf ("error on read of child wait pipe %p, %E", vchild.rd_proc_pipe); + system_printf ("error on read of child wait pipe %p, %E", vchild.rd_proc_pipe); break; } diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 4260f8807e..cf43aa9335 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -413,11 +413,7 @@ proc_terminate () to 1 iff it is a Cygwin process. */ if (!have_execed || !have_execed_cygwin) chld_procs[i]->ppid = 1; - /* Attempt to exit the wait_thread cleanly via CancelSynchronousIo - before falling back to the (explicitly dangerous) cross-thread - termination */ - if (chld_procs[i].wait_thread - && !CancelSynchronousIo (chld_procs[i].wait_thread->thread_handle ())) + if (chld_procs[i].wait_thread) chld_procs[i].wait_thread->terminate_thread (); /* Release memory associated with this process unless it is 'myself'. 'myself' is only in the chld_procs table when we've execed. We @@ -1203,11 +1199,7 @@ remove_proc (int ci) { if (have_execed) { - /* Attempt to exit the wait_thread cleanly via CancelSynchronousIo - before falling back to the (explicitly dangerous) cross-thread - termination */ - if (_my_tls._ctinfo != chld_procs[ci].wait_thread - && !CancelSynchronousIo (chld_procs[ci].wait_thread->thread_handle ())) + if (_my_tls._ctinfo != chld_procs[ci].wait_thread) chld_procs[ci].wait_thread->terminate_thread (); } else if (chld_procs[ci] && chld_procs[ci]->exists ()) From 5453f9fab649b5fc02b2d6cdb8411c8fbd0b7409 Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Wed, 27 Nov 2024 11:22:49 -0800 Subject: [PATCH 103/116] Cygwin: cache IsWow64Process2 host arch in wincap. This was already used in the FAST_CWD check, and could be used in a couple other places. I found the "emulated"/process value returned from the function largely useless, so I did not cache it. It is useless because, as the docs say, it is set to IMAGE_FILE_MACHINE_UNKNOWN (0) if the process is not running under WOW64, but Microsoft also doesn't consider x64-on-ARM64 to be WOW64, so it is set to 0 regardless if the process is ARM64 or x64. You can tell the difference via GetProcessInformation(ProcessMachineTypeInfo), but for the current process even that's overkill: what we really want to know is the IMAGE_FILE_MACHINE_* constant for the Cygwin dll itself, which is conveniently located in memory already, so cache that in wincap also for easy comparisons. Signed-off-by: Jeremy Drake (cherry picked from commit 46f7bcc1e575826f6d3e4a5770ae61423d9be5a9) --- winsup/cygwin/local_includes/wincap.h | 4 ++++ winsup/cygwin/path.cc | 6 ++---- winsup/cygwin/wincap.cc | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/winsup/cygwin/local_includes/wincap.h b/winsup/cygwin/local_includes/wincap.h index c14872787c..250866f061 100644 --- a/winsup/cygwin/local_includes/wincap.h +++ b/winsup/cygwin/local_includes/wincap.h @@ -42,6 +42,8 @@ class wincapc RTL_OSVERSIONINFOEXW version; char osnam[40]; const void *caps; + USHORT host_mach; + USHORT cygwin_mach; bool _is_server; public: @@ -61,6 +63,8 @@ class wincapc { return (size_t) system_info.dwAllocationGranularity; } const char *osname () const { return osnam; } const DWORD build_number () const { return version.dwBuildNumber; } + const USHORT host_machine () const { return host_mach; } + const USHORT cygwin_machine () const { return cygwin_mach; } #define IMPLEMENT(cap) cap() const { return ((wincaps *) this->caps)->cap; } diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index f8afd4c594..5d2f0a5ed4 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -4826,14 +4826,12 @@ find_fast_cwd_pointer () static fcwd_access_t ** find_fast_cwd () { - USHORT emulated, hosted; fcwd_access_t **f_cwd_ptr; - /* First check if we're running in WOW64 on ARM64 emulating AMD64. Skip + /* First check if we're running on an ARM64 system. Skip fetching FAST_CWD pointer as long as there's no solution for finding it on that system. */ - if (IsWow64Process2 (GetCurrentProcess (), &emulated, &hosted) - && hosted == IMAGE_FILE_MACHINE_ARM64) + if (wincap.host_machine () == IMAGE_FILE_MACHINE_ARM64) return NULL; /* Fetch the pointer but don't set the global fast_cwd_ptr yet. First diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc index 30d9c14e8d..deecf8ba51 100644 --- a/winsup/cygwin/wincap.cc +++ b/winsup/cygwin/wincap.cc @@ -235,9 +235,15 @@ static const wincaps wincap_11 = { wincapc wincap __attribute__((section (".cygwin_dll_common"), shared)); +extern IMAGE_DOS_HEADER +__image_base__; + void wincapc::init () { + PIMAGE_NT_HEADERS ntheader; + USHORT emul_mach; + if (caps) return; // already initialized @@ -282,4 +288,17 @@ wincapc::init () __small_sprintf (osnam, "NT-%d.%d", version.dwMajorVersion, version.dwMinorVersion); + + if (!IsWow64Process2 (GetCurrentProcess (), &emul_mach, &host_mach)) + { + /* If IsWow64Process2 succeeded, it filled in host_mach. Assume the only + way it fails for the current process is that we're running on an OS + version where it's not implemented yet. As such, the only realistic + option for host_mach is AMD64 */ + host_mach = IMAGE_FILE_MACHINE_AMD64; + } + + ntheader = (PIMAGE_NT_HEADERS)((LPBYTE) &__image_base__ + + __image_base__.e_lfanew); + cygwin_mach = ntheader->FileHeader.Machine; } From 985e2654b8498dea90f240be8af40f1ddc9bb7a8 Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Wed, 27 Nov 2024 11:26:50 -0800 Subject: [PATCH 104/116] Cygwin: uname: add host machine tag to sysname. If the Cygwin dll's architecture is different from the host system's architecture, append an additional tag that indicates the host system architecture (the Cygwin dll's architecture is already indicated in machine). Signed-off-by: Jeremy Drake (cherry picked from commit 7923059bff6c120c6fb74b63c7553ea345c0a8f3) --- winsup/cygwin/uname.cc | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/winsup/cygwin/uname.cc b/winsup/cygwin/uname.cc index a978363f1c..ba73edda43 100644 --- a/winsup/cygwin/uname.cc +++ b/winsup/cygwin/uname.cc @@ -51,13 +51,27 @@ uname_x (struct utsname *name) __try { char buf[NI_MAXHOST + 1] ATTRIBUTE_NONSTRING; + int n; memset (name, 0, sizeof (*name)); /* sysname */ const char* sysname = get_sysname(); - __small_sprintf (name->sysname, "%s_%s-%u", - sysname, - wincap.osname (), wincap.build_number ()); + n = __small_sprintf (name->sysname, "%s_%s-%u", + sysname, + wincap.osname (), wincap.build_number ()); + if (wincap.host_machine () != wincap.cygwin_machine ()) + { + switch (wincap.host_machine ()) + { + case IMAGE_FILE_MACHINE_ARM64: + n = stpcpy (name->sysname + n, "-ARM64") - name->sysname; + break; + default: + n += __small_sprintf (name->sysname + n, "-%04y", + (int) wincap.host_machine ()); + break; + } + } /* nodename */ memset (buf, 0, sizeof buf); cygwin_gethostname (buf, sizeof buf - 1); From cac55e8ee551009389c14b4d2ba4624a629d7f4d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 20 Feb 2015 13:56:22 +0000 Subject: [PATCH 105/116] Handle 8-bit characters under LOCALE=C Even when the character set is specified as ASCII, we should handle data outside the 7-bit range gracefully by simply copying it, even if it is technically no longer ASCII. This fixes several of Git for Windows' tests, e.g. t7400. Signed-off-by: Johannes Schindelin --- winsup/cygwin/strfuncs.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/winsup/cygwin/strfuncs.cc b/winsup/cygwin/strfuncs.cc index 66667bdb3a..54b9ba7aea 100644 --- a/winsup/cygwin/strfuncs.cc +++ b/winsup/cygwin/strfuncs.cc @@ -1146,7 +1146,11 @@ _sys_mbstowcs (mbtowc_p f_mbtowc, wchar_t *dst, size_t dlen, const char *src, to store them in a symmetric way. */ bytes = 1; if (dst) +#ifdef STRICTLY_7BIT_ASCII *ptr = L'\xf000' | *pmbs; +#else + *ptr = *pmbs; +#endif memset (&ps, 0, sizeof ps); } From 3d08a3ff56eef78823f6b668995dcd082edb8ad7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Feb 2024 07:37:45 +0000 Subject: [PATCH 106/116] Bump actions/checkout from 2 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 4. - [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/v2...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/cygwin.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cygwin.yml b/.github/workflows/cygwin.yml index 5ae4ef9d59..e780428035 100644 --- a/.github/workflows/cygwin.yml +++ b/.github/workflows/cygwin.yml @@ -18,7 +18,7 @@ jobs: HAS_SSH_KEY: ${{ secrets.SSH_KEY != '' }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # install build tools - name: Install build tools @@ -99,7 +99,7 @@ jobs: # endings, but this could still be dangerous e.g if we need symlinks in the # repo) - run: git config --global core.autocrlf input - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # install cygwin and build tools - name: Install Cygwin From 6990ce7e94d985ccaf4c1b83de6e612af503e172 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 20 Feb 2015 11:54:47 +0000 Subject: [PATCH 107/116] Mention the extremely useful small_printf() function It came in real handy while debugging an issue that strace 'fixed'. Signed-off-by: Johannes Schindelin --- winsup/cygwin/DevDocs/how-to-debug-cygwin.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/winsup/cygwin/DevDocs/how-to-debug-cygwin.txt b/winsup/cygwin/DevDocs/how-to-debug-cygwin.txt index 61e91c88d5..953d375864 100644 --- a/winsup/cygwin/DevDocs/how-to-debug-cygwin.txt +++ b/winsup/cygwin/DevDocs/how-to-debug-cygwin.txt @@ -126,3 +126,9 @@ set CYGWIN_DEBUG=cat.exe:gdb.exe program will crash, probably in small_printf. At that point, a 'bt' command should show you the offending call to strace_printf with the improper format string. + +9. Debug output without strace + + If you cannot use gdb, or if the program behaves differently using strace + for whatever reason, you can still use the small_printf() function to + output debugging messages directly to stderr. From 9fd31575f7082da9a216ba987e9bdbacd6af462b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 6 Feb 2024 18:45:41 +0100 Subject: [PATCH 108/116] dependabot: help keeping GitHub Actions versions up to date 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 --- .github/dependabot.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..22d5376407 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file +# especially +# 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 + +version: 2 +updates: + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" From 8b2144fadccafcbc790ec71137b72932adda49dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A7=88=EB=88=84=EC=97=98?= Date: Mon, 9 Mar 2015 16:24:43 +0100 Subject: [PATCH 109/116] Fixed path converting with non ascii char. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a non ascii char is at the beginning of a path the current conversion destroys the path. This fix will prevent this with an extra check for non-ascii UTF-8 characters. Helped-by: Johannes Schindelin Signed-off-by: 마누엘 --- winsup/cygwin/msys2_path_conv.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/msys2_path_conv.cc b/winsup/cygwin/msys2_path_conv.cc index 4c0cc82cf2..0dc086aae9 100644 --- a/winsup/cygwin/msys2_path_conv.cc +++ b/winsup/cygwin/msys2_path_conv.cc @@ -399,7 +399,7 @@ path_type find_path_start_and_type(const char** src, int recurse, const char* en } it = *src; - while (!isalnum(*it) && *it != '/' && *it != '\\' && *it != ':' && *it != '-' && *it != '.') { + while (!isalnum(*it) && !(0x80 & *it) && *it != '/' && *it != '\\' && *it != ':' && *it != '-' && *it != '.') { recurse = true; it = ++*src; if (it == end || *it == '\0') return NONE; From 31f90127b8cb4c046a98d4aba5ca3034a000a0fc Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 20 Aug 2020 12:22:05 +0200 Subject: [PATCH 110/116] Do not try to sync with Cygwin This is a forked repository... Signed-off-by: Johannes Schindelin --- .github/workflows/sync-with-cygwin.yml | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 .github/workflows/sync-with-cygwin.yml diff --git a/.github/workflows/sync-with-cygwin.yml b/.github/workflows/sync-with-cygwin.yml deleted file mode 100644 index 57bd30e5da..0000000000 --- a/.github/workflows/sync-with-cygwin.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: sync-with-cygwin - -# File: .github/workflows/repo-sync.yml - -on: - workflow_dispatch: - schedule: - - cron: "42 * * * *" -jobs: - repo-sync: - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - name: Fetch Cygwin's latest master and tags - run: | - git init --bare - # Potentially use git://sourceware.org/git/newlib-cygwin.git directly, but GitHub seems more reliable - git fetch https://github.com/cygwin/cygwin master:refs/heads/cygwin/master 'refs/tags/*:refs/tags/*' - - name: Push to our fork - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - git push https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY refs/heads/cygwin/master 'refs/tags/*:refs/tags/*' From e05ee9217c75a5910d111b407f2026e439e67daf Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 18 Dec 2015 20:19:57 +0100 Subject: [PATCH 111/116] Make paths' WCS->MBS conversion explicit * dcrt0.cc (dll_crt0_1), dtable.cc (handle_to_fn), environ.cc (environ_init, getwinenveq, build_env), external.cc (fillout_pinfo), fhandler_disk_file.cc (__DIR_mounts::eval_ino, fhandler_disk_file::readdir_helper), fhandler_netdrive.cc (fhandler_netdrive::readdir), fhandler_process.cc (format_process_winexename, format_process_maps, format_process_stat, format_process_status), fhandler_procsys.cc (fill_filebuf, fhandler_procsys::readdir), mount.cc (fs_info::update, mount_info::create_root_entry, mount_info::conv_to_posix_path, mount_info::from_fstab_line), nlsfuncs.cc (internal_setlocale), path.cc (path_conv::check, sysmlink_info::check_shortcut, symlink_info::check_sysfile, symlink_info::check_reparse_point, symlink_info::check_nfs_symlink, cygwin_conv_path, cygwin_conv_path_list, cwdstuff::get_error_desc, cwdstuff::get), strfuncs.cc (sys_wcstombs_no_path, sys_wcstombs_alloc_no_path), uinfo.cc (ontherange, fetch_from_path, cygheap_pwdgrp::get_home, cygheap_pwdgrp::get_shell, cygheap_pwdgrp::get_gecos), wchar.h (sys_wcstombs_no_path, sys_wcstombs_alloc_no_path): Convert call sites of the sys_wcstombs*() family to specify explicitly when the parameter refers to a path or file name, to avoid future misconversions. Detailed explanation: The sys_wcstombs() function contains special handling for paths/file names, to work around file name restriction on Windows that are unexpected in the POSIX context of Cygwin. We actually do not want that special handling for WCS strings that do *not* refer to paths or file names. Neither do we want to convert those special file names unless they come from inside Cygwin: if the source of the string value is the Windows API, we *know* it cannot be such a special file name because Windows itself would not be able to handle it in the way Cygwin does. So let's switch the previous sys_wcstombs()/sys_wcstombs_no_path() (and the *_alloc* variant) around to sys_wcstombs_path()/sys_wcstombs(). We do this for several reasons: - whenever a call site wants to convert a WCS representation of a path or file name to an MBS one, it should be made very clear that we *want* the special file name conversion to happen. - it is shorter to read and write. - future calls to sys_wcstombs() will not incur unwanted conversion by accident (it is easy for unsuspecting programmers to assume that the function name "sys_wcstombs()" refers to a regular text conversion that has nothing to do with paths or filenames). By keeping the name sys_wcstombs() (and not switching to sys_wcstombs_path()), the following call sites are implicitly changed to *exclude* the special path/file name conversion: cygheap.h (get_drive): Cannot contain special characters external.cc (cygwin_internal): Refers to user/domain names, not paths fhandler_clipboard.cc (fhandler_dev_clipboard::read): Is not a path or file name but characters from the Windows clipboard fhandler_console.cc: (dev_console::con_to_str): Is not a path or file name but characters from the console fhandler_registry.cc (encode_regname): Is a registry key, not a path or filename fhandler_registry.cc (multi_wcstombs): All call sites pass registry values, not paths or filenames fhandler_registry.cc (fstat): Is a registry value, not a path or filename fhandler_registry.cc (fill_filebuf): Is a registry value, not a path or filename net.cc (get_ipv4fromreg): Is a registry value, not a path or filename net.cc (get_friendlyname): Is a device name, not a path or filename netdb.cc (open_system_file): Is from outside Cygwin smallprint.cc (__small_vsprintf): Is a free text, not a path or filename strfuncs.cc (strlwr): Should preserve the characters from the private page if there are any strfuncs.cc (strupr): Should preserve the characters from the private page if there are any uinfo.cc (cygheap_user::init): Refers to a user name, not a path or filename uinfo.cc (pwdgrp::fetch_account_from_windows): Refers to value from outside Cygwin By keeping the function name sys_wcstombs_alloc() (and not changing it to sys_wcstombs_alloc_path()), the following call sites are implicitly changed to *exclude* the special path/file name conversion: ldap.cc (cyg_ldap::remap_uid): Refers to a user name, not a path or filename ldap.cc (cyg_ldap::remap_gid): Refers to a group name, not a path or filename pinfo.cc (_pinfo::cmdline): Refers to a command line from Windows, outside Cygwin uinfo.cc (cygheap_user::env_logsrv): Is a server name, not a path or filename uinfo.cc (cygheap_user::env_domain): Refers to the user/domain name, not a path or filename uinfo.cc (cygheap_user::env_userprofile): Refers to Windows' idea of a path, outside Cygwin uinfo.cc (cygheap_user::env_systemroot): Refers to Windows' idea of a path, outside Cygwin uinfo.cc (fetch_from_description): Refers to values from outside of Cygwin uinfo.cc (cygheap_pwdgrp::get_gecos): Refers to user/domain name and email address, not path nor filename Signed-off-by: Johannes Schindelin --- winsup/cygwin/dcrt0.cc | 4 ++-- winsup/cygwin/dtable.cc | 2 +- winsup/cygwin/environ.cc | 8 ++++---- winsup/cygwin/external.cc | 2 +- winsup/cygwin/fhandler/disk_file.cc | 4 ++-- winsup/cygwin/fhandler/netdrive.cc | 6 +++--- winsup/cygwin/fhandler/process.cc | 11 ++++++----- winsup/cygwin/fhandler/procsys.cc | 11 ++++++----- winsup/cygwin/local_includes/wchar.h | 16 +++++++-------- winsup/cygwin/mount.cc | 8 ++++---- winsup/cygwin/nlsfuncs.cc | 2 +- winsup/cygwin/path.cc | 29 ++++++++++++++-------------- winsup/cygwin/uinfo.cc | 20 +++++++++---------- 13 files changed, 63 insertions(+), 60 deletions(-) diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 351d32d8e3..049e003796 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -912,9 +912,9 @@ dll_crt0_1 (void *) if (!__argc) { PWCHAR wline = GetCommandLineW (); - size_t size = sys_wcstombs_no_path (NULL, 0, wline) + 1; + size_t size = sys_wcstombs (NULL, 0, wline) + 1; char *line = (char *) alloca (size); - sys_wcstombs_no_path (line, size, wline); + sys_wcstombs (line, size, wline); /* Scan the command line and build argv. Expand wildcards if not called from another cygwin process. */ diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc index 3c40e0fa3d..141029f811 100644 --- a/winsup/cygwin/dtable.cc +++ b/winsup/cygwin/dtable.cc @@ -1028,7 +1028,7 @@ handle_to_fn (HANDLE h, char *posix_fn) if (wcsncasecmp (w32, DEVICE_PREFIX, DEVICE_PREFIX_LEN) != 0 || !QueryDosDeviceW (NULL, fnbuf, sizeof (fnbuf) / sizeof (WCHAR))) { - sys_wcstombs (posix_fn, NT_MAX_PATH, w32, w32len); + sys_wcstombs_path (posix_fn, NT_MAX_PATH, w32, w32len); return false; } diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 4e049211e9..529535a580 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -918,7 +918,7 @@ win32env_to_cygenv (PWCHAR rawenv, bool posify) eventually want to use them). */ for (i = 0, w = rawenv; *w != L'\0'; w = wcschr (w, L'\0') + 1, i++) { - sys_wcstombs_alloc_no_path (&newp, HEAP_NOTHEAP, w); + sys_wcstombs_alloc (&newp, HEAP_NOTHEAP, w); if (i >= envc) envp = (char **) realloc (envp, (4 + (envc += 100)) * sizeof (char *)); envp[i] = newp; @@ -978,7 +978,7 @@ getwinenveq (const char *name, size_t namelen, int x) int totlen = GetEnvironmentVariableW (name0, valbuf, 32768); if (totlen > 0) { - totlen = sys_wcstombs_no_path (NULL, 0, valbuf) + 1; + totlen = sys_wcstombs (NULL, 0, valbuf) + 1; if (x == HEAP_1_STR) totlen += namelen; else @@ -986,7 +986,7 @@ getwinenveq (const char *name, size_t namelen, int x) char *p = (char *) cmalloc_abort ((cygheap_types) x, totlen); if (namelen) strcpy (p, name); - sys_wcstombs_no_path (p + namelen, totlen, valbuf); + sys_wcstombs (p + namelen, totlen, valbuf); debug_printf ("using value from GetEnvironmentVariable for '%W'", name0); return p; } @@ -1144,7 +1144,7 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, for (winnum = 0, var = cwinenv; *var; ++winnum, var = wcschr (var, L'\0') + 1) - sys_wcstombs_alloc_no_path (&winenv[winnum], HEAP_NOTHEAP, var); + sys_wcstombs_alloc (&winenv[winnum], HEAP_NOTHEAP, var); } DestroyEnvironmentBlock (cwinenv); /* Eliminate variables which are already available in envp, as well as diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc index 33863d8001..353375a984 100644 --- a/winsup/cygwin/external.cc +++ b/winsup/cygwin/external.cc @@ -92,7 +92,7 @@ fillout_pinfo (pid_t pid, int winpid) ep.rusage_self = p->rusage_self; ep.rusage_children = p->rusage_children; ep.progname[0] = '\0'; - sys_wcstombs(ep.progname, MAX_PATH, p->progname); + sys_wcstombs_path (ep.progname, MAX_PATH, p->progname); ep.strace_mask = 0; ep.version = EXTERNAL_PINFO_VERSION; diff --git a/winsup/cygwin/fhandler/disk_file.cc b/winsup/cygwin/fhandler/disk_file.cc index 794c8ebcac..70b7765dc0 100644 --- a/winsup/cygwin/fhandler/disk_file.cc +++ b/winsup/cygwin/fhandler/disk_file.cc @@ -2412,7 +2412,7 @@ fhandler_disk_file::readdir_helper (DIR *dir, dirent *de, DWORD w32_err, char *p = stpcpy (file, pc.get_posix ()); if (p[-1] != '/') *p++ = '/'; - sys_wcstombs (p, NT_MAX_PATH - (p - file), + sys_wcstombs_path (p, NT_MAX_PATH - (p - file), fname->Buffer, fname->Length / sizeof (WCHAR)); path_conv fpath (file, PC_SYM_NOFOLLOW); if (fpath.issymlink ()) @@ -2433,7 +2433,7 @@ fhandler_disk_file::readdir_helper (DIR *dir, dirent *de, DWORD w32_err, } } - sys_wcstombs (de->d_name, NAME_MAX + 1, fname->Buffer, + sys_wcstombs_path (de->d_name, NAME_MAX + 1, fname->Buffer, fname->Length / sizeof (WCHAR)); /* Don't try to optimize relative to dir->__d_position. On several diff --git a/winsup/cygwin/fhandler/netdrive.cc b/winsup/cygwin/fhandler/netdrive.cc index 58ab8811b0..0b71d4ba29 100644 --- a/winsup/cygwin/fhandler/netdrive.cc +++ b/winsup/cygwin/fhandler/netdrive.cc @@ -283,15 +283,15 @@ fhandler_netdrive::readdir (DIR *dir, dirent *de) tp.u_get (&ds); RtlInitUnicodeString (&ss, bs); RtlDowncaseUnicodeString (&ds, &ss, FALSE); - sys_wcstombs (de->d_name, sizeof de->d_name, + sys_wcstombs_path (de->d_name, sizeof de->d_name, ds.Buffer, ds.Length / sizeof (WCHAR)); de->d_ino = hash_path_name (get_ino (), de->d_name); } else { - sys_wcstombs (de->d_name, sizeof de->d_name, bs); + sys_wcstombs_path (de->d_name, sizeof de->d_name, bs); char *rpath = tp.c_get (); - sys_wcstombs (rpath, NT_MAX_PATH, nro->lpRemoteName); + sys_wcstombs_path (rpath, NT_MAX_PATH, nro->lpRemoteName); de->d_ino = readdir_get_ino (rpath, false); /* We can't trust remote inode numbers of only 32 bit. That means, remote NT4 NTFS, as well as shares of Samba version < 3.0. */ diff --git a/winsup/cygwin/fhandler/process.cc b/winsup/cygwin/fhandler/process.cc index 1e5e83b4ab..a63030b65c 100644 --- a/winsup/cygwin/fhandler/process.cc +++ b/winsup/cygwin/fhandler/process.cc @@ -574,10 +574,10 @@ static off_t format_process_winexename (void *data, char *&destbuf) { _pinfo *p = (_pinfo *) data; - size_t len = sys_wcstombs (NULL, 0, p->progname); + size_t len = sys_wcstombs_path (NULL, 0, p->progname); destbuf = (char *) crealloc_abort (destbuf, len + 1); /* With trailing \0 for backward compat reasons. */ - sys_wcstombs (destbuf, len + 1, p->progname); + sys_wcstombs_path (destbuf, len + 1, p->progname); return len; } @@ -1051,7 +1051,7 @@ format_process_maps (void *data, char *&destbuf) drive_maps.fixup_if_match (msi->SectionFileName.Buffer); if (mount_table->conv_to_posix_path (dosname, posix_modname, 0)) - sys_wcstombs (posix_modname, NT_MAX_PATH, dosname); + sys_wcstombs_path (posix_modname, NT_MAX_PATH, dosname); stat (posix_modname, &st); } else if (!threads.fill_if_match (cur.abase, mb.Type, @@ -1108,7 +1108,7 @@ format_process_stat (void *data, char *&destbuf) else { PWCHAR last_slash = wcsrchr (p->progname, L'\\'); - sys_wcstombs (cmd, NAME_MAX + 1, + sys_wcstombs_path (cmd, NAME_MAX + 1, last_slash ? last_slash + 1 : p->progname); int len = strlen (cmd); if (len > 4) @@ -1215,7 +1215,8 @@ format_process_status (void *data, char *&destbuf) bool fetch_siginfo = false; PWCHAR last_slash = wcsrchr (p->progname, L'\\'); - sys_wcstombs (cmd, NAME_MAX + 1, last_slash ? last_slash + 1 : p->progname); + sys_wcstombs_path (cmd, NAME_MAX + 1, + last_slash ? last_slash + 1 : p->progname); int len = strlen (cmd); if (len > 4) { diff --git a/winsup/cygwin/fhandler/procsys.cc b/winsup/cygwin/fhandler/procsys.cc index 4fa00481ad..2f957beb5b 100644 --- a/winsup/cygwin/fhandler/procsys.cc +++ b/winsup/cygwin/fhandler/procsys.cc @@ -236,10 +236,11 @@ fhandler_procsys::fill_filebuf () NtClose (h); if (!NT_SUCCESS (status)) goto unreadable; - len = sys_wcstombs (NULL, 0, target.Buffer, target.Length / sizeof (WCHAR)); + len = sys_wcstombs_path (NULL, 0, + target.Buffer, target.Length / sizeof (WCHAR)); filebuf = (char *) crealloc_abort (filebuf, procsys_len + len + 1); - sys_wcstombs (fnamep = stpcpy (filebuf, procsys), len + 1, target.Buffer, - target.Length / sizeof (WCHAR)); + sys_wcstombs_path (fnamep = stpcpy (filebuf, procsys), len + 1, + target.Buffer, target.Length / sizeof (WCHAR)); while ((fnamep = strchr (fnamep, '\\'))) *fnamep = '/'; return true; @@ -377,8 +378,8 @@ fhandler_procsys::readdir (DIR *dir, dirent *de) res = ENMFILE; else { - sys_wcstombs (de->d_name, NAME_MAX + 1, dbi->ObjectName.Buffer, - dbi->ObjectName.Length / sizeof (WCHAR)); + sys_wcstombs_path (de->d_name, NAME_MAX + 1, dbi->ObjectName.Buffer, + dbi->ObjectName.Length / sizeof (WCHAR)); de->d_ino = hash_path_name (get_ino (), de->d_name); if (RtlEqualUnicodeString (&dbi->ObjectTypeName, &ro_u_natdir, FALSE)) de->d_type = DT_DIR; diff --git a/winsup/cygwin/local_includes/wchar.h b/winsup/cygwin/local_includes/wchar.h index 606559a6ab..c6ec5d8758 100644 --- a/winsup/cygwin/local_includes/wchar.h +++ b/winsup/cygwin/local_includes/wchar.h @@ -173,29 +173,29 @@ extern size_t _sys_wcstombs_alloc (char **dst_p, int type, const wchar_t *src, size_t nwc, bool is_path); static inline size_t -sys_wcstombs (char *dst, size_t len, const wchar_t * src, - size_t nwc = (size_t) -1) +sys_wcstombs_path (char *dst, size_t len, const wchar_t * src, + size_t nwc = (size_t) -1) { return _sys_wcstombs (dst, len, src, nwc, true); } static inline size_t -sys_wcstombs_no_path (char *dst, size_t len, const wchar_t * src, - size_t nwc = (size_t) -1) +sys_wcstombs (char *dst, size_t len, const wchar_t * src, + size_t nwc = (size_t) -1) { return _sys_wcstombs (dst, len, src, nwc, false); } static inline size_t -sys_wcstombs_alloc (char **dst_p, int type, const wchar_t *src, - size_t nwc = (size_t) -1) +sys_wcstombs_alloc_path (char **dst_p, int type, const wchar_t *src, + size_t nwc = (size_t) -1) { return _sys_wcstombs_alloc (dst_p, type, src, nwc, true); } static inline size_t -sys_wcstombs_alloc_no_path (char **dst_p, int type, const wchar_t *src, - size_t nwc = (size_t) -1) +sys_wcstombs_alloc (char **dst_p, int type, const wchar_t *src, + size_t nwc = (size_t) -1) { return _sys_wcstombs_alloc (dst_p, type, src, nwc, false); } diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc index bd6ec2a7a1..8ebfb14034 100644 --- a/winsup/cygwin/mount.cc +++ b/winsup/cygwin/mount.cc @@ -506,7 +506,7 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol) { /* The filesystem name is only used in fillout_mntent and only if the filesystem isn't one of the well-known filesystems anyway. */ - sys_wcstombs (fsn, sizeof fsn, ffai_buf.ffai.FileSystemName, + sys_wcstombs_path (fsn, sizeof fsn, ffai_buf.ffai.FileSystemName, ffai_buf.ffai.FileSystemNameLength / sizeof (WCHAR)); strlwr (fsn); } @@ -547,7 +547,7 @@ mount_info::create_root_entry (const PWCHAR root) /* Create a default root dir derived from the location of the Cygwin DLL. The entry is immutable, unless the "override" option is given in /etc/fstab. */ char native_root[PATH_MAX]; - sys_wcstombs (native_root, PATH_MAX, root); + sys_wcstombs_path (native_root, PATH_MAX, root); assert (*native_root != '\0'); if (add_item (native_root, "/", MOUNT_SYSTEM | MOUNT_IMMUTABLE | MOUNT_AUTOMATIC | MOUNT_NOACL) @@ -941,7 +941,7 @@ mount_info::conv_to_posix_path (PWCHAR src_path, char *posix_path, } tmp_pathbuf tp; char *buf = tp.c_get (); - sys_wcstombs (buf, NT_MAX_PATH, src_path); + sys_wcstombs_path (buf, NT_MAX_PATH, src_path); int ret = conv_to_posix_path (buf, posix_path, ccp_flags); if (changed) src_path[0] = L'C'; @@ -1275,7 +1275,7 @@ mount_info::from_fstab_line (char *line, bool user) { tmp_pathbuf tp; char *mb_tmp = tp.c_get (); - sys_wcstombs (mb_tmp, PATH_MAX, tmp); + sys_wcstombs_path (mb_tmp, PATH_MAX, tmp); mount_flags |= MOUNT_USER_TEMP; int res = mount_table->add_item (mb_tmp, posix_path, mount_flags); diff --git a/winsup/cygwin/nlsfuncs.cc b/winsup/cygwin/nlsfuncs.cc index f57465a4f2..57af967c1a 100644 --- a/winsup/cygwin/nlsfuncs.cc +++ b/winsup/cygwin/nlsfuncs.cc @@ -1776,7 +1776,7 @@ internal_setlocale () if (w_path) { char *c_path = tp.c_get (); - sys_wcstombs (c_path, 32768, w_path); + sys_wcstombs_path (c_path, 32768, w_path); setenv ("PATH", c_path, 1); } } diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 5d2f0a5ed4..f89e631931 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -621,7 +621,8 @@ path_conv::check (const UNICODE_STRING *src, unsigned opt, char *path = tp.c_get (); user_shared->warned_msdos = true; - sys_wcstombs (path, NT_MAX_PATH, src->Buffer, src->Length / sizeof (WCHAR)); + sys_wcstombs_path (path, NT_MAX_PATH, + src->Buffer, src->Length / sizeof (WCHAR)); path_conv::check (path, opt, suffixes); } @@ -2550,7 +2551,7 @@ symlink_info::check_shortcut (HANDLE h) if (*(PWCHAR) cp == 0xfeff) /* BOM */ { char *tmpbuf = tp.c_get (); - if (sys_wcstombs (tmpbuf, NT_MAX_PATH, (PWCHAR) (cp + 2)) + if (sys_wcstombs_path (tmpbuf, NT_MAX_PATH, (PWCHAR) (cp + 2)) > SYMLINK_MAX) return 0; res = posixify (tmpbuf); @@ -2631,7 +2632,7 @@ symlink_info::check_sysfile (HANDLE h) else srcbuf += 2; char *tmpbuf = tp.c_get (); - if (sys_wcstombs (tmpbuf, NT_MAX_PATH, (PWCHAR) srcbuf) + if (sys_wcstombs_path (tmpbuf, NT_MAX_PATH, (PWCHAR) srcbuf) > SYMLINK_MAX) debug_printf ("symlink string too long"); else @@ -2899,8 +2900,8 @@ symlink_info::check_reparse_point (HANDLE h, bool remote) path_flags |= ret; if (ret & PATH_SYMLINK) { - sys_wcstombs (srcbuf, SYMLINK_MAX + 7, symbuf.Buffer, - symbuf.Length / sizeof (WCHAR)); + sys_wcstombs_path (srcbuf, SYMLINK_MAX + 7, symbuf.Buffer, + symbuf.Length / sizeof (WCHAR)); /* A symlink is never a directory. */ fileattr &= ~FILE_ATTRIBUTE_DIRECTORY; return posixify (srcbuf); @@ -2934,7 +2935,7 @@ symlink_info::check_nfs_symlink (HANDLE h) { PWCHAR spath = (PWCHAR) (pffei->EaName + pffei->EaNameLength + 1); - res = sys_wcstombs (contents, SYMLINK_MAX + 1, + res = sys_wcstombs_path (contents, SYMLINK_MAX + 1, spath, pffei->EaValueLength); path_flags |= PATH_SYMLINK; } @@ -4151,7 +4152,7 @@ cygwin_conv_path (cygwin_conv_path_t what, const void *from, void *to, } PUNICODE_STRING up = p.get_nt_native_path (); buf = tp.c_get (); - sys_wcstombs (buf, NT_MAX_PATH, + sys_wcstombs_path (buf, NT_MAX_PATH, up->Buffer, up->Length / sizeof (WCHAR)); /* Convert native path to standard DOS path. */ if (!strncmp (buf, "\\??\\", 4)) @@ -4164,11 +4165,11 @@ cygwin_conv_path (cygwin_conv_path_t what, const void *from, void *to, { /* Device name points to somewhere else in the NT namespace. Use GLOBALROOT prefix to convert to Win32 path. */ - char *p = buf + sys_wcstombs (buf, NT_MAX_PATH, + char *p = buf + sys_wcstombs_path (buf, NT_MAX_PATH, ro_u_globalroot.Buffer, ro_u_globalroot.Length / sizeof (WCHAR)); - sys_wcstombs (p, NT_MAX_PATH - (p - buf), + sys_wcstombs_path (p, NT_MAX_PATH - (p - buf), up->Buffer, up->Length / sizeof (WCHAR)); } lsiz = strlen (buf) + 1; @@ -4478,8 +4479,8 @@ cygwin_conv_path_list (cygwin_conv_path_t what, const void *from, void *to, switch (what & CCP_CONVTYPE_MASK) { case CCP_WIN_W_TO_POSIX: - if (!sys_wcstombs_alloc (&winp, HEAP_NOTHEAP, (const wchar_t *) from, - (size_t) -1)) + if (!sys_wcstombs_alloc_path (&winp, HEAP_NOTHEAP, + (const wchar_t *) from, (size_t) -1)) return -1; what = (what & ~CCP_CONVTYPE_MASK) | CCP_WIN_A_TO_POSIX; from = (const void *) winp; @@ -5253,9 +5254,9 @@ cwdstuff::get_error_desc () const void cwdstuff::reset_posix (wchar_t *w_cwd) { - size_t len = sys_wcstombs (NULL, (size_t) -1, w_cwd); + size_t len = sys_wcstombs_path (NULL, (size_t) -1, w_cwd); posix = (char *) crealloc_abort (posix, len + 1); - sys_wcstombs (posix, len + 1, w_cwd); + sys_wcstombs_path (posix, len + 1, w_cwd); } char * @@ -5280,7 +5281,7 @@ cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen) if (!need_posix) { tocopy = tp.c_get (); - sys_wcstombs (tocopy, NT_MAX_PATH, win32.Buffer, + sys_wcstombs_path (tocopy, NT_MAX_PATH, win32.Buffer, win32.Length / sizeof (WCHAR)); } else diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index 81d9529824..9e7c239437 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -385,12 +385,12 @@ cygheap_user::ontherange (homebodies what, struct passwd *pw) { if (ui->usri3_home_dir_drive && *ui->usri3_home_dir_drive) { - sys_wcstombs (homepath_env_buf, NT_MAX_PATH, + sys_wcstombs_path (homepath_env_buf, NT_MAX_PATH, ui->usri3_home_dir_drive); strcat (homepath_env_buf, "\\"); } else if (ui->usri3_home_dir && *ui->usri3_home_dir) - sys_wcstombs (homepath_env_buf, NT_MAX_PATH, + sys_wcstombs_path (homepath_env_buf, NT_MAX_PATH, ui->usri3_home_dir); } if (ui) @@ -400,7 +400,7 @@ cygheap_user::ontherange (homebodies what, struct passwd *pw) if (!homepath_env_buf[0] && get_user_profile_directory (get_windows_id (win_id), profile, MAX_PATH)) - sys_wcstombs (homepath_env_buf, NT_MAX_PATH, profile); + sys_wcstombs_path (homepath_env_buf, NT_MAX_PATH, profile); /* Last fallback: Cygwin root dir. */ if (!homepath_env_buf[0]) cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, @@ -919,7 +919,7 @@ fetch_from_path (cyg_ldap *pldap, PUSER_INFO_3 ui, cygpsid &sid, PCWSTR str, } } *w = L'\0'; - sys_wcstombs_alloc (&ret, HEAP_NOTHEAP, wpath); + sys_wcstombs_alloc_path (&ret, HEAP_NOTHEAP, wpath); return ret; } @@ -987,7 +987,7 @@ cygheap_pwdgrp::get_home (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom, { val = pldap->get_string_attribute (L"cygwinHome"); if (val && *val) - sys_wcstombs_alloc (&home, HEAP_NOTHEAP, val); + sys_wcstombs_alloc_path (&home, HEAP_NOTHEAP, val); } break; case NSS_SCHEME_UNIX: @@ -995,7 +995,7 @@ cygheap_pwdgrp::get_home (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom, { val = pldap->get_string_attribute (L"unixHomeDirectory"); if (val && *val) - sys_wcstombs_alloc (&home, HEAP_NOTHEAP, val); + sys_wcstombs_alloc_path (&home, HEAP_NOTHEAP, val); } break; case NSS_SCHEME_DESC: @@ -1020,7 +1020,7 @@ cygheap_pwdgrp::get_home (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom, home = (char *) cygwin_create_path (CCP_WIN_W_TO_POSIX, val); else - sys_wcstombs_alloc (&home, HEAP_NOTHEAP, val); + sys_wcstombs_alloc_path (&home, HEAP_NOTHEAP, val); } } break; @@ -1090,7 +1090,7 @@ cygheap_pwdgrp::get_shell (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom, { val = pldap->get_string_attribute (L"cygwinShell"); if (val && *val) - sys_wcstombs_alloc (&shell, HEAP_NOTHEAP, val); + sys_wcstombs_alloc_path (&shell, HEAP_NOTHEAP, val); } break; case NSS_SCHEME_UNIX: @@ -1098,7 +1098,7 @@ cygheap_pwdgrp::get_shell (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom, { val = pldap->get_string_attribute (L"loginShell"); if (val && *val) - sys_wcstombs_alloc (&shell, HEAP_NOTHEAP, val); + sys_wcstombs_alloc_path (&shell, HEAP_NOTHEAP, val); } break; case NSS_SCHEME_DESC: @@ -1123,7 +1123,7 @@ cygheap_pwdgrp::get_shell (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom, shell = (char *) cygwin_create_path (CCP_WIN_W_TO_POSIX, val); else - sys_wcstombs_alloc (&shell, HEAP_NOTHEAP, val); + sys_wcstombs_alloc_path (&shell, HEAP_NOTHEAP, val); } } break; From 64dfcd63798a42eeed61b8028aeaf372472312d0 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Wed, 20 May 2015 16:32:52 +0200 Subject: [PATCH 112/116] Allow native symlinks to non-existing targets in 'nativestrict' mode Windows native symlinks must match the type of their target (file or directory), otherwise native Windows tools will fail. Creating symlinks in 'nativestrict' mode currently requires the target to exist in order to check its type. However, the target of a symlink can change at any time after the symlink has been created. Thus users of native symlinks must be prepared to deal with type mismatches anyway. Checking the target type at symlink creation time is not a good reason to violate the symlink() API specification. In 'nativestrict' mode, always create native symlinks. Choose the symlink type according to the target if it exists. Otherwise check the target path for a trailing '/' as hint to create a directory symlink. This allows callers to explicitly specify the expected target type, e.g.: $ ln -s test/ link-to-test $ mkdir test Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- winsup/cygwin/path.cc | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 5d2f0a5ed4..3623aec507 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -1865,7 +1865,7 @@ symlink_native (const char *oldpath, path_conv &win32_newpath) path_conv win32_oldpath; PUNICODE_STRING final_oldpath, final_newpath; UNICODE_STRING final_oldpath_buf; - DWORD flags; + DWORD flags = 0; if (isabspath (oldpath)) { @@ -1926,14 +1926,39 @@ symlink_native (const char *oldpath, path_conv &win32_newpath) wcpcpy (e_old, c_old); } } - /* If the symlink target doesn't exist, don't create native symlink. - Otherwise the directory flag in the symlink is potentially wrong - when the target comes into existence, and native tools will fail. - This is so screwball. This is no problem on AFS, fortunately. */ - if (!win32_oldpath.exists () && !win32_oldpath.fs_is_afs ()) + + /* The directory flag in the symlink must match the target type, + otherwise native tools will fail (fortunately this is no problem + on AFS). Do our best to guess the symlink type correctly. */ + if (win32_oldpath.exists () || win32_oldpath.fs_is_afs ()) { - SetLastError (ERROR_FILE_NOT_FOUND); - return -1; + /* If the target exists (or on AFS), check the target type. Note + that this may still be wrong if the target is changed after + creating the symlink (e.g. in bulk operations such as rsync, + unpacking archives or VCS checkouts). */ + if (win32_oldpath.isdir ()) + flags |= SYMBOLIC_LINK_FLAG_DIRECTORY; + } + else + { + if (allow_winsymlinks == WSYM_nativestrict) + { + /* In nativestrict mode, if the target does not exist, use + trailing '/' in the target path as hint to create a + directory symlink. */ + ssize_t len = strlen(oldpath); + if (len && isdirsep(oldpath[len - 1])) + flags |= SYMBOLIC_LINK_FLAG_DIRECTORY; + } + else + { + /* In native mode, if the target does not exist, fall back + to creating a Cygwin symlink file (or in case of MSys: + try to copy the (non-existing) target, which will of + course fail). */ + SetLastError (ERROR_FILE_NOT_FOUND); + return -1; + } } /* Don't allow native symlinks to Cygwin special files. However, the caller shoud know because this case shouldn't be covered by the @@ -1962,7 +1987,6 @@ symlink_native (const char *oldpath, path_conv &win32_newpath) final_oldpath->Buffer[1] = L'\\'; } /* Try to create native symlink. */ - flags = win32_oldpath.isdir () ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0; if (wincap.has_unprivileged_createsymlink ()) flags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; if (!CreateSymbolicLinkW (final_newpath->Buffer, final_oldpath->Buffer, From 2ff02fd6f3328e48d6ebe6991b5ec282a75f1afe Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 21 Nov 2019 14:21:01 +0100 Subject: [PATCH 113/116] Use MB_CUR_MAX == 6 by default Internally, Cygwin already uses __utf8_mbtowc(), even if it still claims to use the "ASCII" charset. But the `MB_CUR_MAX` value (which is not actually a constant, but dependent on the current locale) was still 1, which broke the initial `globify()` call while parsing the the command-line in `build_argv()` for non-ASCII arguments. This fixes https://github.com/git-for-windows/git/issues/2189 Signed-off-by: Johannes Schindelin --- newlib/libc/locale/lctype.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/newlib/libc/locale/lctype.c b/newlib/libc/locale/lctype.c index a07ab68124..3f118e98c7 100644 --- a/newlib/libc/locale/lctype.c +++ b/newlib/libc/locale/lctype.c @@ -25,7 +25,12 @@ #define LCCTYPE_SIZE (sizeof(struct lc_ctype_T) / sizeof(char *)) +#ifdef __CYGWIN__ +/* Cygwin uses __utf8_mbtowc() by default, therefore mb_cur_max := 6 */ +static char numone[] = { '\x06', '\0'}; +#else static char numone[] = { '\1', '\0'}; +#endif const struct lc_ctype_T _C_ctype_locale = { "ASCII", /* codeset */ From e1c6154bd29c01f6d5efee7630c3d5feb70833e1 Mon Sep 17 00:00:00 2001 From: Mikael Larsson <95430516+chirpnot@users.noreply.github.com> Date: Thu, 10 Mar 2022 17:26:42 +0000 Subject: [PATCH 114/116] Change the default base address for x86_64 This might break things, but it turns out several Windows libraries like to be loaded at 0x180000000. This causes a problem, because `msys-2.0.dll` loads at `0x180040000` and expects `0x180000000-0x180040000` to be available. A problem arises when Antiviruses (or other DLL hooking mechanisms) load a DLL whose preferred load address is `0x180000000` and fits in size before `0x180010000`: 1. `msys-2.0.dll` loads and fills `0x180010000-0x180040000` assuming no shared console structure is going to be needed. 2. Another DLL loads and fills `0x180000000-0x18000xxxx` 3. `msys-2.0.dll` tries to load `0x180000000-0x180010000` but it's not available. It falls back to another address, but down the line something else fails. This bug triggers when using subshells (e.g.: `git clone --recursive`). The MSYS2 runtime should be able to work around the address conflict, but the code is failing in some way or other... Signed-off-by: Johannes Schindelin Signed-off-by: Mikael Larsson <95430516+chirpnot@users.noreply.github.com> --- winsup/cygwin/cygwin.din | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index 76e88df2fc..f9d458e40e 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -1,4 +1,4 @@ -LIBRARY "msys-2.0.dll" BASE=0x180040000 +LIBRARY "msys-2.0.dll" BASE=0x210040000 EXPORTS # Exported variables From 9ba6664c8b10045fc621e5f86bd1e105cda4f222 Mon Sep 17 00:00:00 2001 From: Richard Glidden Date: Thu, 24 Aug 2023 13:36:10 -0400 Subject: [PATCH 115/116] msys2-runtime: restore fast path for current user primary group Commit a5bcfe616c7e removed an optimization that fetches the default group from the current user token, as it is sometimes not accurate such as when groups like the builtin Administrators group is the primary group. However, removing this optimization causes extremely poor performance when connected to some Active Directory environments. Restored this optimization as the default behaviour, and added a `group: db-accurate` option to `nsswitch.conf` that can be used to disable the optimization in cases where accurate group information is required. This fixes https://github.com/git-for-windows/git/issues/4459 Signed-off-by: Richard Glidden --- winsup/cygwin/include/sys/cygwin.h | 3 ++- winsup/cygwin/local_includes/cygheap.h | 1 + winsup/cygwin/uinfo.cc | 30 ++++++++++++++++++++------ winsup/doc/ntsec.xml | 20 ++++++++++++++++- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h index 6383646cc7..6b2f647724 100644 --- a/winsup/cygwin/include/sys/cygwin.h +++ b/winsup/cygwin/include/sys/cygwin.h @@ -219,7 +219,8 @@ enum enum { NSS_SRC_FILES = 1, - NSS_SRC_DB = 2 + NSS_SRC_DB = 2, + NSS_SRC_DB_ACCURATE = 4 }; /* Enumeration source constants for CW_SETENT called from mkpasswd/mkgroup. */ diff --git a/winsup/cygwin/local_includes/cygheap.h b/winsup/cygwin/local_includes/cygheap.h index b6acdf7f18..b38cb9d1d7 100644 --- a/winsup/cygwin/local_includes/cygheap.h +++ b/winsup/cygwin/local_includes/cygheap.h @@ -406,6 +406,7 @@ class cygheap_pwdgrp inline int nss_pwd_src () const { return pwd_src; } /* CW_GETNSS_PWD_SRC */ inline bool nss_grp_files () const { return !!(grp_src & NSS_SRC_FILES); } inline bool nss_grp_db () const { return !!(grp_src & NSS_SRC_DB); } + inline bool nss_grp_db_accurate () const { return !!(grp_src & NSS_SRC_DB_ACCURATE); } inline int nss_grp_src () const { return grp_src; } /* CW_GETNSS_GRP_SRC */ inline bool nss_cygserver_caching () const { return caching; } inline void nss_disable_cygserver_caching () { caching = false; } diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index 9e7c239437..71234c18ae 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -637,6 +637,11 @@ cygheap_pwdgrp::nss_init_line (const char *line) *src |= NSS_SRC_DB; c += 2; } + else if (NSS_CMP ("db-accurate")) + { + *src |= NSS_SRC_DB | NSS_SRC_DB_ACCURATE; + c += 11; + } else { c += strcspn (c, " \t"); @@ -1952,6 +1957,7 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap) gid_t gid = ILLEGAL_GID; bool is_domain_account = true; PCWSTR domain = NULL; + bool get_default_group_from_current_user_token = false; char *shell = NULL; char *home = NULL; char *gecos = NULL; @@ -2449,9 +2455,19 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap) uid = posix_offset + sid_sub_auth_rid (sid); if (!is_group () && acc_type == SidTypeUser) { - /* Default primary group. Make the educated guess that the user - is in group "Domain Users" or "None". */ - gid = posix_offset + DOMAIN_GROUP_RID_USERS; + /* Default primary group. If the sid is the current user, and + we are not configured for accurate mode, fetch + the default group from the current user token, otherwise make + the educated guess that the user is in group "Domain Users" + or "None". */ + if (!cygheap->pg.nss_grp_db_accurate() && sid == cygheap->user.sid ()) + { + get_default_group_from_current_user_token = true; + gid = posix_offset + + sid_sub_auth_rid (cygheap->user.groups.pgsid); + } + else + gid = posix_offset + DOMAIN_GROUP_RID_USERS; } if (is_domain_account) @@ -2462,9 +2478,11 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap) /* On AD machines, use LDAP to fetch domain account infos. */ if (cygheap->dom.primary_dns_name ()) { - /* Fetch primary group from AD and overwrite the one we - just guessed above. */ - if (cldap->fetch_ad_account (sid, false, domain)) + /* For the current user we got correctly cased username and + the primary group via process token. For any other user + we fetch it from AD and overwrite it. */ + if (!get_default_group_from_current_user_token + && cldap->fetch_ad_account (sid, false, domain)) { if ((val = cldap->get_account_name ())) wcscpy (name, val); diff --git a/winsup/doc/ntsec.xml b/winsup/doc/ntsec.xml index 687789076c..fd5b472b61 100644 --- a/winsup/doc/ntsec.xml +++ b/winsup/doc/ntsec.xml @@ -930,7 +930,16 @@ The two lines starting with the keywords passwd: and information from. files means, fetch the information from the corresponding file in the /etc directory. db means, fetch the information from the Windows account databases, the SAM -for local accounts, Active Directory for domain account. Examples: +for local accounts, Active Directory for domain account. For the current +user, the default group is obtained from the current user token to avoid +additional lookups to the group database. db-accurate +is only valid on group: line, and performs the same +lookups as the db option, but disables using the +current user token to retrieve the default group as this optimization +is not accurate in all cases. For example, if you run a native process +with the primary group set to the Administrators builtin group, the +db option will return a non-existent group as primary +group. Examples: @@ -949,6 +958,15 @@ Read passwd entries only from /etc/passwd. Read group entries only from SAM/AD. + + group: db-accurate + + + +Read group entries only from SAM/AD. Force the use of the group database +for the current user. + + group: files # db From 67bdfc7ab0448278166f94d6fc9c529f6ae796ce Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 10 Oct 2024 19:52:47 +0200 Subject: [PATCH 116/116] Fix SSH hangs It was reported in https://github.com/git-for-windows/git/issues/5199 that as of v3.5.4, cloning or fetching via SSH is hanging indefinitely. Bisecting the problem points to 555afcb2f3 (Cygwin: select: set pipe writable only if PIPE_BUF bytes left, 2024-08-18). That commit's intention seems to look at the write buffer, and only report the pipe as writable if there are more than one page (4kB) available. However, the number that is looked up is the number of bytes that are already in the buffer, ready to be read, and further analysis shows that in the scenario described in the report, the number of available bytes is substantially below `PIPE_BUF`, but as long as they are not handled, there is apparently a dead-lock. Since the old logic worked, and the new logic causes a dead-lock, let's essentially revert 555afcb2f3 (Cygwin: select: set pipe writable only if PIPE_BUF bytes left, 2024-08-18). Note: This is not a straight revert, as the code in question has been modified subsequently, and trying to revert the original commit would cause merge conflicts. Therefore, the diff looks very different from the reverse diff of the commit whose logic is reverted. Signed-off-by: Johannes Schindelin --- winsup/cygwin/select.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index bc02c3f9d4..2c09b14d1c 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -776,7 +776,7 @@ peek_pipe (select_record *s, bool from_select) } ssize_t n = pipe_data_available (s->fd, fh, h, PDA_SELECT | PDA_WRITE); select_printf ("write: %s, n %d", fh->get_name (), n); - gotone += s->write_ready = (n >= PIPE_BUF); + gotone += s->write_ready = (n > 0); if (n < 0 && s->except_selected) gotone += s->except_ready = true; } @@ -990,7 +990,7 @@ peek_fifo (select_record *s, bool from_select) ssize_t n = pipe_data_available (s->fd, fh, fh->get_handle (), PDA_SELECT | PDA_WRITE); select_printf ("write: %s, n %d", fh->get_name (), n); - gotone += s->write_ready = (n >= PIPE_BUF); + gotone += s->write_ready = (n > 0); if (n < 0 && s->except_selected) gotone += s->except_ready = true; } @@ -1416,7 +1416,7 @@ peek_pty_slave (select_record *s, bool from_select) { ssize_t n = pipe_data_available (s->fd, fh, h, PDA_SELECT | PDA_WRITE); select_printf ("write: %s, n %d", fh->get_name (), n); - gotone += s->write_ready = (n >= PIPE_BUF); + gotone += s->write_ready = (n > 0); if (n < 0 && s->except_selected) gotone += s->except_ready = true; }