From 97b7873cba1ffd7e467cc7159a9bf6cf519994ac Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 6 Nov 2023 13:17:32 -0500 Subject: [PATCH 01/48] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index f40fcc60..0a3905b2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2023.11.06, Version 1.47.0 (Stable) +2023.11.06, Version 1.47.0 (Stable), be6b81a352d17513c95be153afcb3148f1a451cd Changes since version 1.46.0: From 815693f71523175f577e3cbdb9cf576d30ea9250 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 6 Nov 2023 13:24:46 -0500 Subject: [PATCH 02/48] Now working on version 1.47.1 Fixes: https://github.com/libuv/libuv/issues/4186 --- configure.ac | 2 +- include/uv/version.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 0a1042ce..1bdcab3f 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.47.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.47.1-dev], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index b17220fc..8a5e3c09 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 47 -#define UV_VERSION_PATCH 0 -#define UV_VERSION_IS_RELEASE 1 -#define UV_VERSION_SUFFIX "" +#define UV_VERSION_PATCH 1 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 4107b8d4db8011beed2cc36e7f92cd5738a1c254 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 7 Nov 2023 10:53:16 -0500 Subject: [PATCH 03/48] misc: remove deprecated stalebot file (#4199) Refs: https://github.com/probot/stale/pull/430 --- .github/stale.yml | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index 6f2fb663..00000000 --- a/.github/stale.yml +++ /dev/null @@ -1,23 +0,0 @@ -# Number of days of inactivity before an issue becomes stale -daysUntilStale: 28 -# Number of days of inactivity before a stale issue is closed -# Set to false to disable. If disabled, issues still need to be closed -# manually, but will remain marked as stale. -daysUntilClose: false -# Issues with these labels will never be considered stale -exemptLabels: - - v2 - - enhancement - - good first issue - - feature-request - - doc - - bug - - not-stale -# Label to use when marking an issue as stale -staleLabel: stale -# Comment to post when marking an issue as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. Thank you for your contributions. -# Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false From f067f50ae47293bf24c8b6232f16e927f1eaf15a Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 10 Nov 2023 18:56:46 +0100 Subject: [PATCH 04/48] build: disable windows asan buildbot (#4215) uv_run_tests.exe fails to start up with exit code 0xC0000135 a.k.a. STATUS_DLL_NOT_FOUND, suggesting it cannot find the ASAN runtime libraries. Disable the buildbot until we figure out how to fix that. Refs: https://github.com/libuv/libuv/issues/4210 --- .github/workflows/CI-win.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CI-win.yml b/.github/workflows/CI-win.yml index 149f9ca0..e66b107d 100644 --- a/.github/workflows/CI-win.yml +++ b/.github/workflows/CI-win.yml @@ -25,7 +25,8 @@ jobs: - {toolchain: Visual Studio 16 2019, arch: x64, server: 2019} - {toolchain: Visual Studio 17 2022, arch: Win32, server: 2022} - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022} - - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: ASAN} + # Currently broken, see https://github.com/libuv/libuv/issues/4210 + #- {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: ASAN} - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: UBSAN} - {toolchain: Visual Studio 17 2022, arch: arm64, server: 2022} steps: From f01219dfb716ceac9cc7dbc70022a197b20d27b3 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 10 Nov 2023 20:17:31 +0100 Subject: [PATCH 05/48] test: don't run tcp_writealot under msan (#4214) The test is prone to time out at the best of times, never mind when running under MemorySanitizer. --- test/test-tcp-writealot.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/test-tcp-writealot.c b/test/test-tcp-writealot.c index ebafb179..fbfa4984 100644 --- a/test/test-tcp-writealot.c +++ b/test/test-tcp-writealot.c @@ -149,8 +149,9 @@ TEST_IMPL(tcp_writealot) { uv_tcp_t client; int r; -#ifdef __TSAN__ - RETURN_SKIP("Test is too slow to run under ThreadSanitizer"); +#if defined(__MSAN__) || defined(__TSAN__) + RETURN_SKIP("Test is too slow to run under " + "MemorySanitizer or ThreadSanitizer"); #endif ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); From 874363f652f0aafb3ed58a4da65940258e5ee713 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 13 Nov 2023 19:25:41 +0100 Subject: [PATCH 06/48] build,win: remove extraneous -lshell32 (#4213) I suggested in https://github.com/libuv/libuv/pull/4182 to add the flag to configure.ac as well but seems we already link to it. I've removed the first one, not the second one, in case libuv is linked with --as-needed. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 1bdcab3f..e556bcc8 100644 --- a/configure.ac +++ b/configure.ac @@ -74,7 +74,7 @@ AM_CONDITIONAL([OS400], [AS_CASE([$host_os],[os400], [true], [false]) AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])]) AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])]) AS_CASE([$host_os],[mingw*], [ - LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32 -ldbghelp -lole32 -luuid -lshell32" + LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -luserenv -luser32 -ldbghelp -lole32 -luuid -lshell32" ]) AS_CASE([$host_os], [solaris2.10], [ CFLAGS="$CFLAGS -DSUNOS_NO_IFADDRS" From 31e4b90c3c45370e21293a984dd59bda70af0494 Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Tue, 14 Nov 2023 04:23:28 -0500 Subject: [PATCH 07/48] unix: ignore ifaddrs with NULL ifa_addr (#4218) Passing this to uv__is_ipv6_link_local() is causing a segmentation fault. Note that the documentation for getifaddrs() explicitly states that this value may be NULL. Signed-off-by: Stephen Gallagher --- src/unix/tcp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index a6b53e59..29f4532e 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -233,8 +233,9 @@ static int uv__ipv6_link_local_scope_id(void) { return 0; for (p = ifa; p != NULL; p = p->ifa_next) - if (uv__is_ipv6_link_local(p->ifa_addr)) - break; + if (p->ifa_addr != NULL) + if (uv__is_ipv6_link_local(p->ifa_addr)) + break; rv = 0; if (p != NULL) { From e135dfe18342c5bdb573964ecf2c5b81613a4b34 Mon Sep 17 00:00:00 2001 From: Hao Hu <33607772+hhu8@users.noreply.github.com> Date: Tue, 14 Nov 2023 18:30:46 +0800 Subject: [PATCH 08/48] unix,win: utility for setting priority for thread (#4075) Add uv_thread_setpriority for setting priority for threads created by uv_thread_create. Add uv_thread_getpriority for getting thread priority. For Linux by default, if the scheduling policy is SCHED_OTHER and the priority is 0, we need to set the nice value. Fixes: https://github.com/libuv/libuv/issues/4051 --- .gitignore | 1 + CMakeLists.txt | 1 + Makefile.am | 1 + docs/src/threading.rst | 15 +++++ include/uv.h | 11 ++++ src/unix/core.c | 125 ++++++++++++++++++++++++++++++++++++ src/win/util.c | 42 ++++++++++++ test/test-list.h | 2 + test/test-thread-priority.c | 105 ++++++++++++++++++++++++++++++ 9 files changed, 303 insertions(+) create mode 100644 test/test-thread-priority.c diff --git a/.gitignore b/.gitignore index 7eb49322..e6a04ec6 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.sdf *.suo .vs/ +.vscode/ *.VC.db *.VC.opendb core diff --git a/CMakeLists.txt b/CMakeLists.txt index 72377851..f7f42773 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -655,6 +655,7 @@ if(LIBUV_BUILD_TESTS) test/test-thread-affinity.c test/test-thread-equal.c test/test-thread.c + test/test-thread-priority.c test/test-threadpool-cancel.c test/test-threadpool.c test/test-timer-again.c diff --git a/Makefile.am b/Makefile.am index 1dca3dd1..ff6f1b8a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -286,6 +286,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-thread-equal.c \ test/test-thread.c \ test/test-thread-affinity.c \ + test/test-thread-priority.c \ test/test-threadpool-cancel.c \ test/test-threadpool.c \ test/test-timer-again.c \ diff --git a/docs/src/threading.rst b/docs/src/threading.rst index d379677a..883218fa 100644 --- a/docs/src/threading.rst +++ b/docs/src/threading.rst @@ -132,6 +132,21 @@ Threads .. c:function:: int uv_thread_join(uv_thread_t *tid) .. c:function:: int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) +.. c:function:: int uv_thread_setpriority(uv_thread_t tid, int priority) + If the function succeeds, the return value is 0. + If the function fails, the return value is less than zero. + Sets the scheduling priority of the thread specified by tid. It requires elevated + privilege to set specific priorities on some platforms. + The priority can be set to the following constants. UV_THREAD_PRIORITY_HIGHEST, + UV_THREAD_PRIORITY_ABOVE_NORMAL, UV_THREAD_PRIORITY_NORMAL, + UV_THREAD_PRIORITY_BELOW_NORMAL, UV_THREAD_PRIORITY_LOWEST. +.. c:function:: int uv_thread_getpriority(uv_thread_t tid, int* priority) + If the function succeeds, the return value is 0. + If the function fails, the return value is less than zero. + Retrieves the scheduling priority of the thread specified by tid. The value in the + output parameter priority is platform dependent. + For Linux, when schedule policy is SCHED_OTHER (default), priority is 0. + Thread-local storage ^^^^^^^^^^^^^^^^^^^^ diff --git a/include/uv.h b/include/uv.h index 5642101c..b1e58e6c 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1284,6 +1284,17 @@ UV_EXTERN uv_pid_t uv_os_getppid(void); UV_EXTERN int uv_os_getpriority(uv_pid_t pid, int* priority); UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority); +enum { + UV_THREAD_PRIORITY_HIGHEST = 2, + UV_THREAD_PRIORITY_ABOVE_NORMAL = 1, + UV_THREAD_PRIORITY_NORMAL = 0, + UV_THREAD_PRIORITY_BELOW_NORMAL = -1, + UV_THREAD_PRIORITY_LOWEST = -2, +}; + +UV_EXTERN int uv_thread_getpriority(uv_thread_t tid, int* priority); +UV_EXTERN int uv_thread_setpriority(uv_thread_t tid, int priority); + UV_EXTERN unsigned int uv_available_parallelism(void); UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count); diff --git a/src/unix/core.c b/src/unix/core.c index 25c5181f..965e7f77 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -90,6 +90,7 @@ extern char** environ; #if defined(__linux__) # include # include +# define gettid() syscall(SYS_gettid) # define uv__accept4 accept4 #endif @@ -1557,6 +1558,130 @@ int uv_os_setpriority(uv_pid_t pid, int priority) { return 0; } +/** + * If the function succeeds, the return value is 0. + * If the function fails, the return value is non-zero. + * for Linux, when schedule policy is SCHED_OTHER (default), priority is 0. + * So the output parameter priority is actually the nice value. +*/ +int uv_thread_getpriority(uv_thread_t tid, int* priority) { + int r; + int policy; + struct sched_param param; +#ifdef __linux__ + pid_t pid = gettid(); +#endif + + if (priority == NULL) + return UV_EINVAL; + + r = pthread_getschedparam(tid, &policy, ¶m); + if (r != 0) + return UV__ERR(errno); + +#ifdef __linux__ + if (SCHED_OTHER == policy && pthread_equal(tid, pthread_self())) { + errno = 0; + r = getpriority(PRIO_PROCESS, pid); + if (r == -1 && errno != 0) + return UV__ERR(errno); + *priority = r; + return 0; + } +#endif + + *priority = param.sched_priority; + return 0; +} + +#ifdef __linux__ +static int set_nice_for_calling_thread(int priority) { + int r; + int nice; + + if (priority < UV_THREAD_PRIORITY_LOWEST || priority > UV_THREAD_PRIORITY_HIGHEST) + return UV_EINVAL; + + pid_t pid = gettid(); + nice = 0 - priority * 2; + r = setpriority(PRIO_PROCESS, pid, nice); + if (r != 0) + return UV__ERR(errno); + return 0; +} +#endif + +/** + * If the function succeeds, the return value is 0. + * If the function fails, the return value is non-zero. +*/ +int uv_thread_setpriority(uv_thread_t tid, int priority) { + int r; + int min; + int max; + int range; + int prio; + int policy; + struct sched_param param; + + if (priority < UV_THREAD_PRIORITY_LOWEST || priority > UV_THREAD_PRIORITY_HIGHEST) + return UV_EINVAL; + + r = pthread_getschedparam(tid, &policy, ¶m); + if (r != 0) + return UV__ERR(errno); + +#ifdef __linux__ +/** + * for Linux, when schedule policy is SCHED_OTHER (default), priority must be 0, + * we should set the nice value in this case. +*/ + if (SCHED_OTHER == policy && pthread_equal(tid, pthread_self())) + return set_nice_for_calling_thread(priority); +#endif + +#ifdef __PASE__ + min = 1; + max = 127; +#else + min = sched_get_priority_min(policy); + max = sched_get_priority_max(policy); +#endif + + if (min == -1 || max == -1) + return UV__ERR(errno); + + range = max - min; + + switch (priority) { + case UV_THREAD_PRIORITY_HIGHEST: + prio = max; + break; + case UV_THREAD_PRIORITY_ABOVE_NORMAL: + prio = min + range * 3 / 4; + break; + case UV_THREAD_PRIORITY_NORMAL: + prio = min + range / 2; + break; + case UV_THREAD_PRIORITY_BELOW_NORMAL: + prio = min + range / 4; + break; + case UV_THREAD_PRIORITY_LOWEST: + prio = min; + break; + default: + return 0; + } + + if (param.sched_priority != prio) { + param.sched_priority = prio; + r = pthread_setschedparam(tid, policy, ¶m); + if (r != 0) + return UV__ERR(errno); + } + + return 0; +} int uv_os_uname(uv_utsname_t* buffer) { struct utsname buf; diff --git a/src/win/util.c b/src/win/util.c index 91d88a54..a96cb915 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1466,6 +1466,48 @@ int uv_os_setpriority(uv_pid_t pid, int priority) { return r; } +int uv_thread_getpriority(uv_thread_t tid, int* priority) { + int r; + + if (priority == NULL) + return UV_EINVAL; + + r = GetThreadPriority(tid); + if (r == THREAD_PRIORITY_ERROR_RETURN) + return uv_translate_sys_error(GetLastError()); + + *priority = r; + return 0; +} + +int uv_thread_setpriority(uv_thread_t tid, int priority) { + int r; + + switch (priority) { + case UV_THREAD_PRIORITY_HIGHEST: + r = SetThreadPriority(tid, THREAD_PRIORITY_HIGHEST); + break; + case UV_THREAD_PRIORITY_ABOVE_NORMAL: + r = SetThreadPriority(tid, THREAD_PRIORITY_ABOVE_NORMAL); + break; + case UV_THREAD_PRIORITY_NORMAL: + r = SetThreadPriority(tid, THREAD_PRIORITY_NORMAL); + break; + case UV_THREAD_PRIORITY_BELOW_NORMAL: + r = SetThreadPriority(tid, THREAD_PRIORITY_BELOW_NORMAL); + break; + case UV_THREAD_PRIORITY_LOWEST: + r = SetThreadPriority(tid, THREAD_PRIORITY_LOWEST); + break; + default: + return 0; + } + + if (r == 0) + return uv_translate_sys_error(GetLastError()); + + return 0; +} int uv_os_uname(uv_utsname_t* buffer) { /* Implementation loosely based on diff --git a/test/test-list.h b/test/test-list.h index d112d07a..f042bc29 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -468,6 +468,7 @@ TEST_DECLARE (thread_rwlock_trylock) TEST_DECLARE (thread_create) TEST_DECLARE (thread_equal) TEST_DECLARE (thread_affinity) +TEST_DECLARE (thread_priority) TEST_DECLARE (dlerror) #if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \ !defined(__sun) @@ -1165,6 +1166,7 @@ TASK_LIST_START TEST_ENTRY (thread_create) TEST_ENTRY (thread_equal) TEST_ENTRY (thread_affinity) + TEST_ENTRY (thread_priority) TEST_ENTRY (dlerror) TEST_ENTRY (ip4_addr) TEST_ENTRY (ip6_addr_link_local) diff --git a/test/test-thread-priority.c b/test/test-thread-priority.c new file mode 100644 index 00000000..0aaf2977 --- /dev/null +++ b/test/test-thread-priority.c @@ -0,0 +1,105 @@ +/* Copyright libuv contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include /* memset */ + +#ifdef __POSIX__ +#include +#include +#endif + +#ifdef _WIN32 +#include +#else +#include +#endif + +uv_sem_t sem; + +static void simple_task(void *args) { + uv_sem_wait(&sem); + printf("in simple_task\n"); +} + +TEST_IMPL(thread_priority) { + int priority; +#ifndef _WIN32 + int min; + int max; + int policy; + struct sched_param param; +#endif + uv_thread_t task_id; + + /* Verify that passing a NULL pointer returns UV_EINVAL. */ + ASSERT_EQ(UV_EINVAL, uv_thread_getpriority(0, NULL)); + ASSERT_OK(uv_sem_init(&sem, 1)); + uv_sem_wait(&sem); + ASSERT_OK(uv_thread_create(&task_id, simple_task, NULL)); + ASSERT_OK(uv_thread_getpriority(task_id, &priority)); + +#ifdef _WIN32 + ASSERT_EQ(priority, THREAD_PRIORITY_NORMAL); +#else + ASSERT_OK(pthread_getschedparam(task_id, &policy, ¶m)); +#ifdef __PASE__ + min = 1; + max = 127; +#else + min = sched_get_priority_min(policy); + max = sched_get_priority_max(policy); +#endif + ASSERT(priority >= min && priority <= max); +#endif + + ASSERT_OK(uv_thread_setpriority(task_id, UV_THREAD_PRIORITY_LOWEST)); + ASSERT_OK(uv_thread_getpriority(task_id, &priority)); + +#ifdef _WIN32 + ASSERT_EQ(priority, THREAD_PRIORITY_LOWEST); +#else + ASSERT_EQ(priority, min); +#endif + +/** + * test set nice value for the calling thread with default schedule policy +*/ +#ifdef __linux__ + ASSERT_OK(uv_thread_getpriority(pthread_self(), &priority)); + ASSERT_EQ(priority, 0); + ASSERT_OK(uv_thread_setpriority(pthread_self(), UV_THREAD_PRIORITY_LOWEST)); + ASSERT_OK(uv_thread_getpriority(pthread_self(), &priority)); + ASSERT_EQ(priority, (0 - UV_THREAD_PRIORITY_LOWEST * 2)); +#endif + + uv_sem_post(&sem); + + ASSERT_OK(uv_thread_join(&task_id)); + + uv_sem_destroy(&sem); + + return 0; +} \ No newline at end of file From d843b7cf7fe77ff2c134e7de9f1ce79fbecda7a6 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 14 Nov 2023 09:26:53 -0500 Subject: [PATCH 09/48] pipe: add back error handling to connect / bind (#4202) This was incorrectly dropped by #4030, where previously connecting to "" might fail eventually, now instead it would return EINVAL and then fail to initialize the struct or call the callback. --- src/unix/pipe.c | 19 +++++++++++++++++-- src/win/pipe.c | 31 ++++++++++++++++++++++--------- test/test-pipe-bind-error.c | 19 ++++++++++++++++++- 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index d332f351..117b8ee5 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -210,7 +210,22 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb) { - uv_pipe_connect2(req, handle, name, strlen(name), 0, cb); + int err; + + err = uv_pipe_connect2(req, handle, name, strlen(name), 0, cb); + + if (err) { + handle->delayed_error = err; + handle->connect_req = req; + + uv__req_init(handle->loop, req, UV_CONNECT); + req->handle = (uv_stream_t*) handle; + req->cb = cb; + uv__queue_init(&req->queue); + + /* Force callback to run on next tick in case of error. */ + uv__io_feed(handle->loop, &handle->io_watcher); + } } @@ -295,7 +310,7 @@ out: handle->connect_req = req; uv__req_init(handle->loop, req, UV_CONNECT); - req->handle = (uv_stream_t*)handle; + req->handle = (uv_stream_t*) handle; req->cb = cb; uv__queue_init(&req->queue); diff --git a/src/win/pipe.c b/src/win/pipe.c index cec72ff7..c5749418 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -834,7 +834,19 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb) { - uv_pipe_connect2(req, handle, name, strlen(name), 0, cb); + uv_loop_t* loop; + int err; + + err = uv_pipe_connect2(req, handle, name, strlen(name), 0, cb); + + if (err) { + loop = handle->loop; + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, err); + uv__insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + } } @@ -844,12 +856,20 @@ int uv_pipe_connect2(uv_connect_t* req, size_t namelen, unsigned int flags, uv_connect_cb cb) { - uv_loop_t* loop = handle->loop; + uv_loop_t* loop; int err; size_t nameSize; HANDLE pipeHandle = INVALID_HANDLE_VALUE; DWORD duplex_flags; + loop = handle->loop; + UV_REQ_INIT(req, UV_CONNECT); + req->handle = (uv_stream_t*) handle; + req->cb = cb; + req->u.connect.pipeHandle = INVALID_HANDLE_VALUE; + req->u.connect.duplex_flags = 0; + req->u.connect.name = NULL; + if (flags & ~UV_PIPE_NO_TRUNCATE) { return UV_EINVAL; } @@ -872,13 +892,6 @@ int uv_pipe_connect2(uv_connect_t* req, } } - UV_REQ_INIT(req, UV_CONNECT); - req->handle = (uv_stream_t*) handle; - req->cb = cb; - req->u.connect.pipeHandle = INVALID_HANDLE_VALUE; - req->u.connect.duplex_flags = 0; - req->u.connect.name = NULL; - if (handle->flags & UV_HANDLE_PIPESERVER) { err = ERROR_INVALID_PARAMETER; goto error; diff --git a/test/test-pipe-bind-error.c b/test/test-pipe-bind-error.c index 381a0084..1dc99e5b 100644 --- a/test/test-pipe-bind-error.c +++ b/test/test-pipe-bind-error.c @@ -33,6 +33,7 @@ static int close_cb_called = 0; +static int connect_cb_called = 0; static void close_cb(uv_handle_t* handle) { @@ -154,6 +155,14 @@ TEST_IMPL(pipe_bind_or_listen_error_after_close) { return 0; } + +static void connect_overlong_cb(uv_connect_t* connect_req, int status) { + ASSERT_EQ(status, UV_EINVAL); + connect_cb_called++; + uv_close((uv_handle_t*) connect_req->handle, close_cb); +} + + TEST_IMPL(pipe_overlong_path) { char path[512]; uv_pipe_t pipe; @@ -170,9 +179,17 @@ TEST_IMPL(pipe_overlong_path) { sizeof(path), UV_PIPE_NO_TRUNCATE, (uv_connect_cb) abort)); - uv_close((uv_handle_t*) &pipe, NULL); ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(UV_EINVAL, uv_pipe_bind(&pipe, "")); + uv_pipe_connect(&req, + &pipe, + "", + (uv_connect_cb) connect_overlong_cb); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(1, close_cb_called); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; From 54d8364c2406758b572621af381f1d83e01ae46c Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 14 Nov 2023 22:09:30 +0100 Subject: [PATCH 10/48] test: check if ipv6 link-local traffic is routable (#4220) Fixes: https://github.com/libuv/libuv/issues/4211 --- test/test-tcp-connect6-error.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/test-tcp-connect6-error.c b/test/test-tcp-connect6-error.c index 1e6d7c78..dc2fce82 100644 --- a/test/test-tcp-connect6-error.c +++ b/test/test-tcp-connect6-error.c @@ -23,6 +23,7 @@ #include "task.h" #include #include +#include static int connect_cb_called = 0; @@ -75,9 +76,13 @@ TEST_IMPL(tcp_connect6_error_fault) { TEST_IMPL(tcp_connect6_link_local) { + uv_interface_address_t* ifs; + uv_interface_address_t* p; struct sockaddr_in6 addr; uv_connect_t req; uv_tcp_t server; + int ok; + int n; if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); @@ -90,6 +95,18 @@ TEST_IMPL(tcp_connect6_link_local) { RETURN_SKIP("Test does not currently work in QEMU"); #endif /* defined(__QEMU__) */ + /* Check there's an interface that routes link-local (fe80::/10) traffic. */ + ASSERT_OK(uv_interface_addresses(&ifs, &n)); + for (p = ifs; p < &ifs[n]; p++) + if (p->address.address6.sin6_family == AF_INET6) + if (!memcmp(&p->address.address6.sin6_addr, "\xfe\x80", 2)) + break; + ok = (p < &ifs[n]); + uv_free_interface_addresses(ifs, n); + + if (!ok) + RETURN_SKIP("IPv6 link-local traffic not supported"); + ASSERT_OK(uv_ip6_addr("fe80::0bad:babe", 1337, &addr)); ASSERT_OK(uv_tcp_init(uv_default_loop(), &server)); From b9421d70665352138557d2d2338656a38ac70691 Mon Sep 17 00:00:00 2001 From: Viacheslav Muravyev Date: Wed, 15 Nov 2023 20:39:17 +0700 Subject: [PATCH 11/48] unix: restore signal disposition to previous one (#4216) Fixes: https://github.com/libuv/libuv/issues/2435 --- src/unix/signal.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/unix/signal.c b/src/unix/signal.c index bc4206e6..2b556708 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -32,11 +32,18 @@ # define SA_RESTART 0 #endif +#define UV__NSIG 128 + typedef struct { uv_signal_t* handle; int signum; } uv__signal_msg_t; +typedef struct { + struct sigaction acts[UV__NSIG]; + char acts_presented_flags[UV__NSIG]; +} uv__sigactions_t; + RB_HEAD(uv__signal_tree_s, uv_signal_s); @@ -50,11 +57,23 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2); static void uv__signal_stop(uv_signal_t* handle); static void uv__signal_unregister_handler(int signum); +static void uv__sigaction_set(int signum, struct sigaction *sa); +static int uv__sigaction_isset(int signum); static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT; static struct uv__signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree); static int uv__signal_lock_pipefd[2] = { -1, -1 }; +static uv__sigactions_t uv__sigactions; + +static void uv__sigaction_set(int signum, struct sigaction *sa) { + uv__sigactions.acts[signum] = *sa; + uv__sigactions.acts_presented_flags[signum] = 1; +} + +static int uv__sigaction_isset(int signum) { + return uv__sigactions.acts_presented_flags[signum] == 0 ? 0 : 1; +} RB_GENERATE_STATIC(uv__signal_tree_s, uv_signal_s, tree_entry, @@ -224,6 +243,7 @@ static void uv__signal_handler(int signum) { static int uv__signal_register_handler(int signum, int oneshot) { /* When this function is called, the signal lock must be held. */ struct sigaction sa; + struct sigaction sa_old; /* XXX use a separate signal stack? */ memset(&sa, 0, sizeof(sa)); @@ -234,10 +254,11 @@ static int uv__signal_register_handler(int signum, int oneshot) { if (oneshot) sa.sa_flags |= SA_RESETHAND; - /* XXX save old action so we can restore it later on? */ - if (sigaction(signum, &sa, NULL)) + if (sigaction(signum, &sa, &sa_old)) return UV__ERR(errno); + uv__sigaction_set(signum, &sa_old); + return 0; } @@ -245,9 +266,10 @@ static int uv__signal_register_handler(int signum, int oneshot) { static void uv__signal_unregister_handler(int signum) { /* When this function is called, the signal lock must be held. */ struct sigaction sa; - - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_DFL; + + assert(uv__sigaction_isset(signum)); + + sa = uv__sigactions.acts[signum]; /* sigaction can only fail with EINVAL or EFAULT; an attempt to deregister a * signal implies that it was successfully registered earlier, so EINVAL From 35da5ded3bd7cc6d21c2a6f3d796299f7e2123b9 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 15 Nov 2023 09:08:49 -0500 Subject: [PATCH 12/48] win: remove check for UV_PIPE_NO_TRUNCATE (#4221) There is no length at which this gets truncated on Windows. The underlying file system will just not successfully connect to a longer path (in WTF-16 characters), which will return an error asynchronously with the existing API. Refs: #4040 --- src/win/pipe.c | 12 ------------ test/test-pipe-bind-error.c | 7 +++++-- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/win/pipe.c b/src/win/pipe.c index c5749418..17e4a520 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -722,12 +722,6 @@ int uv_pipe_bind2(uv_pipe_t* handle, return UV_EINVAL; } - if (flags & UV_PIPE_NO_TRUNCATE) { - if (namelen > 256) { - return UV_EINVAL; - } - } - if (handle->flags & UV_HANDLE_BOUND) { return UV_EINVAL; } @@ -886,12 +880,6 @@ int uv_pipe_connect2(uv_connect_t* req, return UV_EINVAL; } - if (flags & UV_PIPE_NO_TRUNCATE) { - if (namelen > 256) { - return UV_EINVAL; - } - } - if (handle->flags & UV_HANDLE_PIPESERVER) { err = ERROR_INVALID_PARAMETER; goto error; diff --git a/test/test-pipe-bind-error.c b/test/test-pipe-bind-error.c index 1dc99e5b..412f23ae 100644 --- a/test/test-pipe-bind-error.c +++ b/test/test-pipe-bind-error.c @@ -164,12 +164,14 @@ static void connect_overlong_cb(uv_connect_t* connect_req, int status) { TEST_IMPL(pipe_overlong_path) { - char path[512]; uv_pipe_t pipe; uv_connect_t req; - memset(path, '@', sizeof(path)); ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe, 0)); + +#ifndef _WIN32 + char path[512]; + memset(path, '@', sizeof(path)); ASSERT_EQ(UV_EINVAL, uv_pipe_bind2(&pipe, path, sizeof(path), UV_PIPE_NO_TRUNCATE)); ASSERT_EQ(UV_EINVAL, @@ -180,6 +182,7 @@ TEST_IMPL(pipe_overlong_path) { UV_PIPE_NO_TRUNCATE, (uv_connect_cb) abort)); ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); +#endif ASSERT_EQ(UV_EINVAL, uv_pipe_bind(&pipe, "")); uv_pipe_connect(&req, From f1444293652cf5478a67b9305271d73ad6d36232 Mon Sep 17 00:00:00 2001 From: matoro <12038583+matoro@users.noreply.github.com> Date: Wed, 15 Nov 2023 17:57:06 -0500 Subject: [PATCH 13/48] linux: disable io_uring on hppa below kernel 6.1.51 (#4224) First kernel with support is 6.1, was only fully functional from .51 onwards: https://lore.kernel.org/all/cb912694-b1fe-dbb0-4d8c-d608f3526905@gmx.de/ Co-authored-by: matoro --- src/unix/linux.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index 8eeb352e..91409bb5 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -487,8 +487,16 @@ static int uv__use_io_uring(void) { use = atomic_load_explicit(&use_io_uring, memory_order_relaxed); if (use == 0) { + use = uv__kernel_version() >= +#if defined(__hppa__) + /* io_uring first supported on parisc in 6.1, functional in .51 */ + /* https://lore.kernel.org/all/cb912694-b1fe-dbb0-4d8c-d608f3526905@gmx.de/ */ + /* 6.1.51 */ 0x060133 +#else /* Older kernels have a bug where the sqpoll thread uses 100% CPU. */ - use = uv__kernel_version() >= /* 5.10.186 */ 0x050ABA ? 1 : -1; + /* 5.10.186 */ 0x050ABA +#endif + ? 1 : -1; /* But users can still enable it if they so desire. */ val = getenv("UV_USE_IO_URING"); From 6be130e1b865af62e6509d4ead9da5c911af5e12 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 16 Nov 2023 09:05:51 +0100 Subject: [PATCH 14/48] unix,win: fix read past end of pipe name buffer (#4209) Passing a socket name without a trailing nul byte to uv_pipe_bind2() or (on Windows) uv_pipe_connect2() resulted in reading beyond the end of the name buffer when copying or converting it. Fix that by copying the socket name to temporary storage first and add the trailing nul byte explicitly. Add a check for embedded nul bytes in the socket name. Fix a small memory leak in the Windows error path of uv_pipe_bind2(). --- src/unix/pipe.c | 29 ++++++++++------ src/win/pipe.c | 66 ++++++++++++++++++++++++++++++------ test/test-pipe-getsockname.c | 26 +++++++++++--- 3 files changed, 96 insertions(+), 25 deletions(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index 117b8ee5..bb2806f5 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -30,6 +30,19 @@ #include +/* Does the file path contain embedded nul bytes? */ +static int includes_nul(const char *s, size_t n) { + if (n == 0) + return 0; +#ifdef __linux__ + /* Accept abstract socket namespace path ("\0/virtual/path"). */ + s++; + n--; +#endif + return NULL != memchr(s, '\0', n); +} + + int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE); handle->shutdown_req = NULL; @@ -65,11 +78,8 @@ int uv_pipe_bind2(uv_pipe_t* handle, if (namelen == 0) return UV_EINVAL; -#ifndef __linux__ - /* Abstract socket namespace only works on Linux. */ - if (*name == '\0') + if (includes_nul(name, namelen)) return UV_EINVAL; -#endif if (flags & UV_PIPE_NO_TRUNCATE) if (namelen > sizeof(saddr.sun_path)) @@ -91,9 +101,11 @@ int uv_pipe_bind2(uv_pipe_t* handle, * automatically since they're not real file system entities. */ if (*name != '\0') { - pipe_fname = uv__strdup(name); + pipe_fname = uv__malloc(namelen + 1); if (pipe_fname == NULL) return UV_ENOMEM; + memcpy(pipe_fname, name, namelen); + pipe_fname[namelen] = '\0'; } err = uv__socket(AF_UNIX, SOCK_STREAM, 0); @@ -117,7 +129,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, /* Success. */ handle->flags |= UV_HANDLE_BOUND; - handle->pipe_fname = pipe_fname; /* NULL or a strdup'ed copy. */ + handle->pipe_fname = pipe_fname; /* NULL or a copy of |name| */ handle->io_watcher.fd = sockfd; return 0; @@ -249,11 +261,8 @@ int uv_pipe_connect2(uv_connect_t* req, if (namelen == 0) return UV_EINVAL; -#ifndef __linux__ - /* Abstract socket namespace only works on Linux. */ - if (*name == '\0') + if (includes_nul(name, namelen)) return UV_EINVAL; -#endif if (flags & UV_PIPE_NO_TRUNCATE) if (namelen > sizeof(saddr.sun_path)) diff --git a/src/win/pipe.c b/src/win/pipe.c index 17e4a520..d5102ed5 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -98,6 +98,14 @@ static void eof_timer_destroy(uv_pipe_t* pipe); static void eof_timer_close_cb(uv_handle_t* handle); +/* Does the file path contain embedded nul bytes? */ +static int includes_nul(const char *s, size_t n) { + if (n == 0) + return 0; + return NULL != memchr(s, '\0', n); +} + + static void uv__unique_pipe_name(char* ptr, char* name, size_t size) { snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId()); } @@ -705,6 +713,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, uv_loop_t* loop = handle->loop; int i, err; uv_pipe_accept_t* req; + char* name_copy; if (flags & ~UV_PIPE_NO_TRUNCATE) { return UV_EINVAL; @@ -718,7 +727,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, return UV_EINVAL; } - if (*name == '\0') { + if (includes_nul(name, namelen)) { return UV_EINVAL; } @@ -730,14 +739,24 @@ int uv_pipe_bind2(uv_pipe_t* handle, return UV_EINVAL; } + name_copy = uv__malloc(namelen + 1); + if (name_copy == NULL) { + return UV_ENOMEM; + } + + memcpy(name_copy, name, namelen); + name_copy[namelen] = '\0'; + if (!(handle->flags & UV_HANDLE_PIPESERVER)) { handle->pipe.serv.pending_instances = default_pending_pipe_instances; } + err = UV_ENOMEM; handle->pipe.serv.accept_reqs = (uv_pipe_accept_t*) uv__malloc(sizeof(uv_pipe_accept_t) * handle->pipe.serv.pending_instances); - if (!handle->pipe.serv.accept_reqs) - return UV_ENOMEM; + if (handle->pipe.serv.accept_reqs == NULL) { + goto error; + } for (i = 0; i < handle->pipe.serv.pending_instances; i++) { req = &handle->pipe.serv.accept_reqs[i]; @@ -747,9 +766,14 @@ int uv_pipe_bind2(uv_pipe_t* handle, req->next_pending = NULL; } - err = uv__convert_utf8_to_utf16(name, &handle->name); - if (err) - return err; + /* TODO(bnoordhuis) Add converters that take a |length| parameter. */ + err = uv__convert_utf8_to_utf16(name_copy, &handle->name); + uv__free(name_copy); + name_copy = NULL; + + if (err) { + goto error; + } /* * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE. @@ -761,9 +785,11 @@ int uv_pipe_bind2(uv_pipe_t* handle, TRUE)) { err = GetLastError(); if (err == ERROR_ACCESS_DENIED) { - err = WSAEADDRINUSE; /* Translates to UV_EADDRINUSE. */ + err = UV_EADDRINUSE; } else if (err == ERROR_PATH_NOT_FOUND || err == ERROR_INVALID_NAME) { - err = WSAEACCES; /* Translates to UV_EACCES. */ + err = UV_EACCES; + } else { + err = uv_translate_sys_error(err); } goto error; } @@ -775,10 +801,13 @@ int uv_pipe_bind2(uv_pipe_t* handle, return 0; error: + uv__free(handle->pipe.serv.accept_reqs); uv__free(handle->name); + uv__free(name_copy); + handle->pipe.serv.accept_reqs = NULL; handle->name = NULL; - return uv_translate_sys_error(err); + return err; } @@ -855,6 +884,7 @@ int uv_pipe_connect2(uv_connect_t* req, size_t nameSize; HANDLE pipeHandle = INVALID_HANDLE_VALUE; DWORD duplex_flags; + char* name_copy; loop = handle->loop; UV_REQ_INIT(req, UV_CONNECT); @@ -876,10 +906,18 @@ int uv_pipe_connect2(uv_connect_t* req, return UV_EINVAL; } - if (*name == '\0') { + if (includes_nul(name, namelen)) { return UV_EINVAL; } + name_copy = uv__malloc(namelen + 1); + if (name_copy == NULL) { + return UV_ENOMEM; + } + + memcpy(name_copy, name, namelen); + name_copy[namelen] = '\0'; + if (handle->flags & UV_HANDLE_PIPESERVER) { err = ERROR_INVALID_PARAMETER; goto error; @@ -890,7 +928,11 @@ int uv_pipe_connect2(uv_connect_t* req, } uv__pipe_connection_init(handle); - err = uv__convert_utf8_to_utf16(name, &handle->name); + /* TODO(bnoordhuis) Add converters that take a |length| parameter. */ + err = uv__convert_utf8_to_utf16(name_copy, &handle->name); + uv__free(name_copy); + name_copy = NULL; + if (err) { err = ERROR_NO_UNICODE_TRANSLATION; goto error; @@ -936,6 +978,8 @@ int uv_pipe_connect2(uv_connect_t* req, return 0; error: + uv__free(name_copy); + if (handle->name) { uv__free(handle->name); handle->name = NULL; diff --git a/test/test-pipe-getsockname.c b/test/test-pipe-getsockname.c index eb09d88f..bac723c6 100644 --- a/test/test-pipe-getsockname.c +++ b/test/test-pipe-getsockname.c @@ -91,16 +91,24 @@ TEST_IMPL(pipe_getsockname) { RETURN_SKIP(NO_SELF_CONNECT); #endif uv_loop_t* loop; + char namebuf[256]; char buf[1024]; + size_t namelen; size_t len; int r; + snprintf(namebuf, sizeof(namebuf), "%s-oob", TEST_PIPENAME); + namelen = sizeof(TEST_PIPENAME) - 1; + loop = uv_default_loop(); ASSERT_NOT_NULL(loop); r = uv_pipe_init(loop, &pipe_server, 0); ASSERT_OK(r); + r = uv_pipe_bind2(&pipe_server, "bad\0path", 8, 0); + ASSERT_EQ(r, UV_EINVAL); + len = sizeof buf; r = uv_pipe_getsockname(&pipe_server, buf, &len); ASSERT_EQ(r, UV_EBADF); @@ -109,9 +117,13 @@ TEST_IMPL(pipe_getsockname) { r = uv_pipe_getpeername(&pipe_server, buf, &len); ASSERT_EQ(r, UV_EBADF); - r = uv_pipe_bind(&pipe_server, TEST_PIPENAME); + r = uv_pipe_bind2(&pipe_server, namebuf, namelen, 0); ASSERT_OK(r); +#ifndef _WIN32 + ASSERT_STR_EQ(pipe_server.pipe_fname, TEST_PIPENAME); +#endif + len = sizeof buf; r = uv_pipe_getsockname(&pipe_server, buf, &len); ASSERT_OK(r); @@ -138,7 +150,13 @@ TEST_IMPL(pipe_getsockname) { r = uv_pipe_getpeername(&pipe_client, buf, &len); ASSERT_EQ(r, UV_EBADF); - uv_pipe_connect(&connect_req, &pipe_client, TEST_PIPENAME, pipe_client_connect_cb); + r = uv_pipe_connect2(&connect_req, + &pipe_client, + namebuf, + namelen, + 0, + pipe_client_connect_cb); + ASSERT_OK(r); len = sizeof buf; r = uv_pipe_getsockname(&pipe_client, buf, &len); @@ -171,7 +189,7 @@ TEST_IMPL(pipe_getsockname_abstract) { buflen = sizeof(buf); memset(buf, 0, sizeof(buf)); ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_server, 0)); - ASSERT_OK(uv_pipe_bind2(&pipe_server, name, sizeof(name), 0)); + ASSERT_OK(uv_pipe_bind2(&pipe_server, name, sizeof(name) - 1, 0)); ASSERT_OK(uv_pipe_getsockname(&pipe_server, buf, &buflen)); ASSERT_MEM_EQ(name, buf, sizeof(name)); ASSERT_OK(uv_listen((uv_stream_t*) &pipe_server, @@ -181,7 +199,7 @@ TEST_IMPL(pipe_getsockname_abstract) { ASSERT_OK(uv_pipe_connect2(&connect_req, &pipe_client, name, - sizeof(name), + sizeof(name) - 1, 0, pipe_client_connect_cb)); ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); From 4785ad6337aac8b78224291f0848f25fc8cb41c9 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Sat, 18 Nov 2023 16:57:40 +0800 Subject: [PATCH 15/48] unix: unbreak macOS < 10.14 (#4230) --- src/unix/fs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 891306da..4de0643a 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -84,7 +84,8 @@ #if defined(__CYGWIN__) || \ (defined(__HAIKU__) && B_HAIKU_VERSION < B_HAIKU_VERSION_1_PRE_BETA_5) || \ - (defined(__sun) && !defined(__illumos__)) + (defined(__sun) && !defined(__illumos__)) || \ + (defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED <= 101300) #define preadv(fd, bufs, nbufs, off) \ pread(fd, (bufs)->iov_base, (bufs)->iov_len, off) #define pwritev(fd, bufs, nbufs, off) \ From bfbe4e38d7253ed5cfa87bfa44ae66fd7bf1957f Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Sat, 18 Nov 2023 18:19:16 +0000 Subject: [PATCH 16/48] aix: disable ipv6 link local (#4229) AIX does not implement ifaddrs and when retrieving the network interfaces with uv_interface_addresses there was a test failure in tcp_connect6_link_local. For now disable ipv6 link local on aix to: 1) fix broken aix build 2) stop blocking libuv upgrade in node Refs: https://github.com/libuv/libuv/pull/4222#issuecomment-1812962233 Refs: https://github.com/nodejs/node/pull/50650 --- src/unix/tcp.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index 29f4532e..f455c53f 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -30,12 +30,8 @@ #include #include -#if defined(__PASE__) -#include -#define ifaddrs ifaddrs_pase -#define getifaddrs Qp2getifaddrs -#define freeifaddrs Qp2freeifaddrs -#else +/* ifaddrs is not implemented on AIX and IBM i PASE */ +#if !defined(_AIX) #include #endif @@ -224,6 +220,10 @@ static int uv__is_ipv6_link_local(const struct sockaddr* addr) { static int uv__ipv6_link_local_scope_id(void) { +/* disable link local on AIX & PASE for now */ +#if defined(_AIX) + return 0; +#else struct sockaddr_in6* a6; struct ifaddrs* ifa; struct ifaddrs* p; @@ -245,6 +245,7 @@ static int uv__ipv6_link_local_scope_id(void) { freeifaddrs(ifa); return rv; +#endif } From 7ba94d39096e54e54c52f813325aa01202eb6acf Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Sun, 19 Nov 2023 08:47:23 -0500 Subject: [PATCH 17/48] doc: move cjihrig to emeriti (#4234) --- MAINTAINERS.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index ff8be88b..41c60cb3 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -4,9 +4,6 @@ libuv is currently managed by the following individuals: * **Ben Noordhuis** ([@bnoordhuis](https://github.com/bnoordhuis)) - GPG key: D77B 1E34 243F BAF0 5F8E 9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis) -* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig)) - - GPG key: 94AE 3667 5C46 4D64 BAFA 68DD 7434 390B DBE9 B9C5 (pubkey-cjihrig) - - GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb) * **Jameson Nash** ([@vtjnash](https://github.com/vtjnash)) - GPG key: AEAD 0A4B 6867 6775 1A0E 4AEF 34A2 5FB1 2824 6514 (pubkey-vtjnash) - GPG key: CFBB 9CA9 A5BE AFD7 0E2B 3C5A 79A6 7C55 A367 9C8B (pubkey2022-vtjnash) @@ -27,6 +24,9 @@ libuv is currently managed by the following individuals: * **Anna Henningsen** ([@addaleax](https://github.com/addaleax)) * **Bartosz Sosnowski** ([@bzoz](https://github.com/bzoz)) * **Bert Belder** ([@piscisaureus](https://github.com/piscisaureus)) +* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig)) + - GPG key: 94AE 3667 5C46 4D64 BAFA 68DD 7434 390B DBE9 B9C5 (pubkey-cjihrig) + - GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb) * **Fedor Indutny** ([@indutny](https://github.com/indutny)) - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny) * **Imran Iqbal** ([@imran-iq](https://github.com/imran-iq)) From fc70430b09c49032d41ae97db26da10e20941e75 Mon Sep 17 00:00:00 2001 From: Bo Anderson Date: Fri, 24 Nov 2023 10:17:52 +0000 Subject: [PATCH 18/48] unix: correct pwritev conditional (#4233) --- src/unix/fs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 4de0643a..9671f0dd 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -85,7 +85,8 @@ #if defined(__CYGWIN__) || \ (defined(__HAIKU__) && B_HAIKU_VERSION < B_HAIKU_VERSION_1_PRE_BETA_5) || \ (defined(__sun) && !defined(__illumos__)) || \ - (defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED <= 101300) + (defined(__APPLE__) && !TARGET_OS_IPHONE && \ + MAC_OS_X_VERSION_MIN_REQUIRED < 110000) #define preadv(fd, bufs, nbufs, off) \ pread(fd, (bufs)->iov_base, (bufs)->iov_len, off) #define pwritev(fd, bufs, nbufs, off) \ From de43f42735700453169efd9bea03f11f96a59dcb Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Fri, 24 Nov 2023 05:18:51 -0500 Subject: [PATCH 19/48] test_fs.c: Fix issue on 32-bit systems using btrfs (#4227) On Fedora's build system, the build environment runs on btrfs. This revealed a bug in the test on i686 systems, where this comparison was being performed as a comparison of two signed integers, but the filesystem type of btrfs happens to use the higher-order bits, resulting in it appearing as a negative value. BTRFS_SUPER_MAGIC 0x9123683e Signed-off-by: Stephen Gallagher --- test/test-fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-fs.c b/test/test-fs.c index 1acdc5c6..ab8a9e07 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -343,7 +343,7 @@ static void statfs_cb(uv_fs_t* req) { defined(__OpenBSD__) || defined(__NetBSD__) ASSERT_OK(stats->f_type); #else - ASSERT_GT(stats->f_type, 0); + ASSERT_UINT64_GT(stats->f_type, 0); #endif ASSERT_GT(stats->f_bsize, 0); From a5c01d4de3695e9d9da34cfd643b5ff0ba582ea7 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 24 Nov 2023 05:22:25 -0500 Subject: [PATCH 20/48] misc: ignore libuv-release-tool files (#4201) --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e6a04ec6..d184d21c 100644 --- a/.gitignore +++ b/.gitignore @@ -75,3 +75,5 @@ cmake-build-debug/ # make dist output libuv-*.tar.* +/dist.libuv.org/ +/libuv-release-tool/ From 5e302730cd29cfeb15d32369dd2edfd9d3c82c11 Mon Sep 17 00:00:00 2001 From: Ardi Nugraha <33378542+ardi-nugraha@users.noreply.github.com> Date: Fri, 1 Dec 2023 04:54:41 +0700 Subject: [PATCH 21/48] win: honor NoDefaultCurrentDirectoryInExePath env var (#4238) Fixes: https://github.com/libuv/libuv/issues/3888 Refs: https://github.com/nodejs/node/issues/46264 --- src/win/process.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/win/process.c b/src/win/process.c index 43059858..117054d4 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -377,11 +377,13 @@ static WCHAR* search_path(const WCHAR *file, } else { dir_end = path; - /* The file is really only a name; look in cwd first, then scan path */ - result = path_search_walk_ext(L"", 0, - file, file_len, - cwd, cwd_len, - name_has_ext); + if (NeedCurrentDirectoryForExePathW(L"")) { + /* The file is really only a name; look in cwd first, then scan path */ + result = path_search_walk_ext(L"", 0, + file, file_len, + cwd, cwd_len, + name_has_ext); + } while (result == NULL) { if (dir_end == NULL || *dir_end == L'\0') { From 12bd89bbc3955f5df5c0a71d32a6cefb2a0d3cfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 11 Dec 2023 09:18:50 +0100 Subject: [PATCH 22/48] idna: fix compilation warning w_target_len is set but unsued in release mode. --- src/idna.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/idna.c b/src/idna.c index 1c0a60cf..3cf79ca9 100644 --- a/src/idna.c +++ b/src/idna.c @@ -400,6 +400,7 @@ void uv_wtf8_to_utf16(const char* source_ptr, } } while (*source_ptr++); + (void)w_target_len; assert(w_target_len == 0); } From a7d5255122ebdf60fd209e1f7201c5dac175677b Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 12 Dec 2023 21:13:31 +0100 Subject: [PATCH 23/48] linux: remove HAVE_IFADDRS_H macro (#4243) Introduced long ago for old Linux/libc flavors libuv no longer supports. We include unconditionally elsewhere so there is no point in special-casing it here. Fixes: https://github.com/libuv/libuv/issues/4242 --- src/unix/linux.c | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index 91409bb5..7402a6fa 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -37,12 +37,16 @@ #include #include +#include +#include #include +#include #include #include #include #include #include +#include #include #include #include @@ -120,25 +124,6 @@ # endif #endif /* __NR_getrandom */ -#define HAVE_IFADDRS_H 1 - -# if defined(__ANDROID_API__) && __ANDROID_API__ < 24 -# undef HAVE_IFADDRS_H -#endif - -#ifdef __UCLIBC__ -# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32 -# undef HAVE_IFADDRS_H -# endif -#endif - -#ifdef HAVE_IFADDRS_H -# include -# include -# include -# include -#endif /* HAVE_IFADDRS_H */ - enum { UV__IORING_SETUP_SQPOLL = 2u, }; @@ -1916,7 +1901,6 @@ nocpuinfo: } -#ifdef HAVE_IFADDRS_H static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) return 1; @@ -1930,14 +1914,8 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { return exclude_type; return !exclude_type; } -#endif int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { -#ifndef HAVE_IFADDRS_H - *count = 0; - *addresses = NULL; - return UV_ENOSYS; -#else struct ifaddrs *addrs, *ent; uv_interface_address_t* address; int i; @@ -2016,7 +1994,6 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { freeifaddrs(addrs); return 0; -#endif } From 1479b76310a38d98eda94db2b7f8a40e04b3ff32 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Tue, 12 Dec 2023 20:19:02 +0000 Subject: [PATCH 24/48] test: skip tcp-write-in-a-row on IBM i (#4197) On IBM i this test fails asserting the write queue size. The test expects the queue size to be greater than 0 but the queue size is 0 on IBM i. https://github.com/libuv/libuv/blob/66160d6973b41040f6b2066a84359147258f60c3/test/test-tcp-write-in-a-row.c#L75 The test expects the write to get queued because the size of the data is larger than the send and receive buffers. https://github.com/libuv/libuv/blob/66160d6973b41040f6b2066a84359147258f60c3/test/test-tcp-write-in-a-row.c#L39-L40 For some reason the request does not seem to get queued on IBM i. The root cause of the issue will need further investigation. Part of #4143 --- test/test-tcp-write-in-a-row.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test-tcp-write-in-a-row.c b/test/test-tcp-write-in-a-row.c index 89304eb5..5c17ed49 100644 --- a/test/test-tcp-write-in-a-row.c +++ b/test/test-tcp-write-in-a-row.c @@ -114,8 +114,9 @@ static void start_server(void) { TEST_IMPL(tcp_write_in_a_row) { #if defined(_WIN32) RETURN_SKIP("tcp_write_in_a_row does not work on Windows"); +#elif defined(__PASE__) + RETURN_SKIP("tcp_write_in_a_row does not work on IBM i PASE"); #else - uv_connect_t connect_req; struct sockaddr_in addr; From 34db4c21b1f3182a74091d927b10bb9830ef6717 Mon Sep 17 00:00:00 2001 From: Anton Bachin Date: Wed, 20 Dec 2023 16:27:13 +0300 Subject: [PATCH 25/48] build,win: work around missing uuid.dll on MinGW (#4261) --- CMakeLists.txt | 1 - configure.ac | 2 +- src/win/process.c | 11 ++++++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f7f42773..f3d1642b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,7 +186,6 @@ if(WIN32) ws2_32 dbghelp ole32 - uuid shell32) list(APPEND uv_sources src/win/async.c diff --git a/configure.ac b/configure.ac index e556bcc8..f9b5aa53 100644 --- a/configure.ac +++ b/configure.ac @@ -74,7 +74,7 @@ AM_CONDITIONAL([OS400], [AS_CASE([$host_os],[os400], [true], [false]) AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])]) AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])]) AS_CASE([$host_os],[mingw*], [ - LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -luserenv -luser32 -ldbghelp -lole32 -luuid -lshell32" + LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -luserenv -luser32 -ldbghelp -lole32 -lshell32" ]) AS_CASE([$host_os], [solaris2.10], [ CFLAGS="$CFLAGS -DSUNOS_NO_IFADDRS" diff --git a/src/win/process.c b/src/win/process.c index 117054d4..6123ea26 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -1212,9 +1212,18 @@ static int uv__kill(HANDLE process_handle, int signum) { (PVOID) dump_folder, &dump_folder_len); if (ret != ERROR_SUCCESS) { + /* Workaround for missing uuid.dll on MinGW. */ + static const GUID FOLDERID_LocalAppData_libuv = { + 0xf1b32785, 0x6fba, 0x4fcf, + {0x9d, 0x55, 0x7b, 0x8e, 0x7f, 0x15, 0x70, 0x91} + }; + /* Default value for `dump_folder` is `%LOCALAPPDATA%\CrashDumps`. */ WCHAR* localappdata; - SHGetKnownFolderPath(&FOLDERID_LocalAppData, 0, NULL, &localappdata); + SHGetKnownFolderPath(&FOLDERID_LocalAppData_libuv, + 0, + NULL, + &localappdata); _snwprintf_s(dump_folder, sizeof(dump_folder), _TRUNCATE, From 8a499e13319f4f02193cf5f3d22ee2c3e247f0a8 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov Date: Fri, 22 Dec 2023 08:30:48 -0300 Subject: [PATCH 26/48] win: stop using deprecated names (#4253) --- CMakeLists.txt | 7 +- src/win/fs-event.c | 2 +- src/win/fs.c | 4 +- src/win/pipe.c | 2 +- src/win/process.c | 10 +- src/win/tty.c | 4 +- test/run-tests.c | 1 + test/runner-win.c | 2 +- test/test-fs-copyfile.c | 3 +- test/test-fs-event.c | 6 +- test/test-fs-readdir.c | 4 +- test/test-fs.c | 181 ++++++++++++++++++---------------- test/test-getters-setters.c | 4 + test/test-metrics.c | 6 +- test/test-poll.c | 5 +- test/test-spawn.c | 9 +- test/test-threadpool-cancel.c | 4 + 17 files changed, 142 insertions(+), 112 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f3d1642b..0a4d8069 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,6 +161,11 @@ list(APPEND uv_cflags ${lint-utf8-msvc} ) check_c_compiler_flag(-fno-strict-aliasing UV_F_STRICT_ALIASING) list(APPEND uv_cflags $<$:-fno-strict-aliasing>) +if (MSVC) + # Error on calling undeclared functions. + list(APPEND uv_cflags "/we4013") +endif() + set(uv_sources src/fs-poll.c src/idna.c @@ -176,7 +181,7 @@ set(uv_sources src/version.c) if(WIN32) - list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0602) + list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0602 _CRT_DECLARE_NONSTDC_NAMES=0) list(APPEND uv_libraries psapi user32 diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 4a0ca1f7..fce41181 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -114,7 +114,7 @@ static int uv__split_path(const WCHAR* filename, WCHAR** dir, } } - *file = wcsdup(filename); + *file = _wcsdup(filename); } else { if (dir) { *dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR)); diff --git a/src/win/fs.c b/src/win/fs.c index 99c8a2bf..b73c17d8 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -407,8 +407,8 @@ void fs__open(uv_fs_t* req) { /* Obtain the active umask. umask() never fails and returns the previous * umask. */ - current_umask = umask(0); - umask(current_umask); + current_umask = _umask(0); + _umask(current_umask); /* convert flags and mode to CreateFile parameters */ switch (flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR)) { diff --git a/src/win/pipe.c b/src/win/pipe.c index d5102ed5..3c8abe1c 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -199,7 +199,7 @@ static void close_pipe(uv_pipe_t* pipe) { if (pipe->u.fd == -1) CloseHandle(pipe->handle); else - close(pipe->u.fd); + _close(pipe->u.fd); pipe->u.fd = -1; pipe->handle = INVALID_HANDLE_VALUE; diff --git a/src/win/process.c b/src/win/process.c index 6123ea26..50161b14 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -26,7 +26,7 @@ #include #include #include -#include /* alloca */ +#include /* _alloca */ #include "uv.h" #include "internal.h" @@ -511,7 +511,7 @@ WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) { } } target[0] = L'\0'; - wcsrev(start); + _wcsrev(start); *(target++) = L'"'; return target; } @@ -615,8 +615,8 @@ int env_strncmp(const wchar_t* a, int na, const wchar_t* b) { assert(b_eq); nb = b_eq - b; - A = alloca((na+1) * sizeof(wchar_t)); - B = alloca((nb+1) * sizeof(wchar_t)); + A = _alloca((na+1) * sizeof(wchar_t)); + B = _alloca((nb+1) * sizeof(wchar_t)); r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, a, na, A, na); assert(r==na); @@ -693,7 +693,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { if (dst_copy == NULL && env_len > 0) { return UV_ENOMEM; } - env_copy = alloca(env_block_count * sizeof(WCHAR*)); + env_copy = _alloca(env_block_count * sizeof(WCHAR*)); ptr = dst_copy; ptr_copy = env_copy; diff --git a/src/win/tty.c b/src/win/tty.c index ac836930..9f8dd698 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -695,7 +695,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, DWORD records_left, records_read; uv_buf_t buf; - off_t buf_used; + _off_t buf_used; assert(handle->type == UV_TTY); assert(handle->flags & UV_HANDLE_TTY_READABLE); @@ -2246,7 +2246,7 @@ void uv__tty_close(uv_tty_t* handle) { if (handle->u.fd == -1) CloseHandle(handle->handle); else - close(handle->u.fd); + _close(handle->u.fd); handle->u.fd = -1; handle->handle = INVALID_HANDLE_VALUE; diff --git a/test/run-tests.c b/test/run-tests.c index 97fec52f..17fb0e0c 100644 --- a/test/run-tests.c +++ b/test/run-tests.c @@ -25,6 +25,7 @@ #ifdef _WIN32 # include +# define read _read #else # include #endif diff --git a/test/runner-win.c b/test/runner-win.c index 61d6f143..6c6e35f7 100644 --- a/test/runner-win.c +++ b/test/runner-win.c @@ -310,7 +310,7 @@ static int clear_line(void) { COORD coord; DWORD written; - handle = (HANDLE)_get_osfhandle(fileno(stderr)); + handle = (HANDLE)_get_osfhandle(_fileno(stderr)); if (handle == INVALID_HANDLE_VALUE) return -1; diff --git a/test/test-fs-copyfile.c b/test/test-fs-copyfile.c index 3f159aeb..3aacf125 100644 --- a/test/test-fs-copyfile.c +++ b/test/test-fs-copyfile.c @@ -74,7 +74,8 @@ static void touch_file(const char* name, unsigned int size) { int r; unsigned int i; - r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT | O_TRUNC, + r = uv_fs_open(NULL, &req, name, + UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_TRUNC, S_IWUSR | S_IRUSR, NULL); uv_fs_req_cleanup(&req); ASSERT_GE(r, 0); diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 7b5c0d8e..0ef51180 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -80,7 +80,9 @@ static void create_file(const char* name) { uv_file file; uv_fs_t req; - r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); + r = uv_fs_open(NULL, &req, name, UV_FS_O_WRONLY | UV_FS_O_CREAT, + S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); file = r; uv_fs_req_cleanup(&req); @@ -95,7 +97,7 @@ static void touch_file(const char* name) { uv_fs_t req; uv_buf_t buf; - r = uv_fs_open(NULL, &req, name, O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &req, name, UV_FS_O_RDWR, 0, NULL); ASSERT_GE(r, 0); file = r; uv_fs_req_cleanup(&req); diff --git a/test/test-fs-readdir.c b/test/test-fs-readdir.c index b6b5b7ff..0f2b4afa 100644 --- a/test/test-fs-readdir.c +++ b/test/test-fs-readdir.c @@ -359,7 +359,7 @@ TEST_IMPL(fs_readdir_non_empty_dir) { r = uv_fs_open(uv_default_loop(), &create_req, "test_dir/file1", - O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, + UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); uv_fs_req_cleanup(&create_req); @@ -373,7 +373,7 @@ TEST_IMPL(fs_readdir_non_empty_dir) { r = uv_fs_open(uv_default_loop(), &create_req, "test_dir/file2", - O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, + UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); uv_fs_req_cleanup(&create_req); diff --git a/test/test-fs.c b/test/test-fs.c index ab8a9e07..fe78117b 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -51,6 +51,9 @@ # ifndef lseek # define lseek _lseek # endif +# define S_IFDIR _S_IFDIR +# define S_IFCHR _S_IFCHR +# define S_IFREG _S_IFREG #endif #define TOO_LONG_NAME_LENGTH 65536 @@ -227,7 +230,7 @@ static void realpath_cb(uv_fs_t* req) { uv_cwd(test_file_abs_buf, &test_file_abs_size); #ifdef _WIN32 strcat(test_file_abs_buf, "\\test_file"); - ASSERT_OK(stricmp(req->ptr, test_file_abs_buf)); + ASSERT_OK(_stricmp(req->ptr, test_file_abs_buf)); #else strcat(test_file_abs_buf, "/test_file"); ASSERT_OK(strcmp(req->ptr, test_file_abs_buf)); @@ -718,12 +721,13 @@ TEST_IMPL(fs_file_noent) { loop = uv_default_loop(); - r = uv_fs_open(NULL, &req, "does_not_exist", O_RDONLY, 0, NULL); + r = uv_fs_open(NULL, &req, "does_not_exist", UV_FS_O_RDONLY, 0, NULL); ASSERT_EQ(r, UV_ENOENT); ASSERT_EQ(req.result, UV_ENOENT); uv_fs_req_cleanup(&req); - r = uv_fs_open(loop, &req, "does_not_exist", O_RDONLY, 0, open_noent_cb); + r = uv_fs_open(loop, &req, "does_not_exist", UV_FS_O_RDONLY, 0, + open_noent_cb); ASSERT_OK(r); ASSERT_OK(open_cb_count); @@ -746,12 +750,12 @@ TEST_IMPL(fs_file_nametoolong) { memset(name, 'a', TOO_LONG_NAME_LENGTH); name[TOO_LONG_NAME_LENGTH] = 0; - r = uv_fs_open(NULL, &req, name, O_RDONLY, 0, NULL); + r = uv_fs_open(NULL, &req, name, UV_FS_O_RDONLY, 0, NULL); ASSERT_EQ(r, UV_ENAMETOOLONG); ASSERT_EQ(req.result, UV_ENAMETOOLONG); uv_fs_req_cleanup(&req); - r = uv_fs_open(loop, &req, name, O_RDONLY, 0, open_nametoolong_cb); + r = uv_fs_open(loop, &req, name, UV_FS_O_RDONLY, 0, open_nametoolong_cb); ASSERT_OK(r); ASSERT_OK(open_cb_count); @@ -786,12 +790,12 @@ TEST_IMPL(fs_file_loop) { ASSERT_OK(r); uv_fs_req_cleanup(&req); - r = uv_fs_open(NULL, &req, "test_symlink", O_RDONLY, 0, NULL); + r = uv_fs_open(NULL, &req, "test_symlink", UV_FS_O_RDONLY, 0, NULL); ASSERT_EQ(r, UV_ELOOP); ASSERT_EQ(req.result, UV_ELOOP); uv_fs_req_cleanup(&req); - r = uv_fs_open(loop, &req, "test_symlink", O_RDONLY, 0, open_loop_cb); + r = uv_fs_open(loop, &req, "test_symlink", UV_FS_O_RDONLY, 0, open_loop_cb); ASSERT_OK(r); ASSERT_OK(open_cb_count); @@ -918,7 +922,7 @@ TEST_IMPL(fs_file_async) { loop = uv_default_loop(); - r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT, + r = uv_fs_open(loop, &open_req1, "test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IRUSR | S_IWUSR, create_cb); ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); @@ -938,7 +942,7 @@ TEST_IMPL(fs_file_async) { ASSERT_EQ(1, close_cb_count); ASSERT_EQ(1, rename_cb_count); - r = uv_fs_open(loop, &open_req1, "test_file2", O_RDWR, 0, open_cb); + r = uv_fs_open(loop, &open_req1, "test_file2", UV_FS_O_RDWR, 0, open_cb); ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); @@ -950,7 +954,7 @@ TEST_IMPL(fs_file_async) { ASSERT_EQ(1, write_cb_count); ASSERT_EQ(1, ftruncate_cb_count); - r = uv_fs_open(loop, &open_req1, "test_file2", O_RDONLY, 0, open_cb); + r = uv_fs_open(loop, &open_req1, "test_file2", UV_FS_O_RDONLY, 0, open_cb); ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); @@ -982,7 +986,8 @@ static void fs_file_sync(int add_flags) { loop = uv_default_loop(); r = uv_fs_open(loop, &open_req1, "test_file", - O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); + UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -998,7 +1003,8 @@ static void fs_file_sync(int add_flags) { ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); - r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR | add_flags, 0, NULL); + r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDWR | add_flags, 0, + NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -1025,7 +1031,7 @@ static void fs_file_sync(int add_flags) { ASSERT_OK(rename_req.result); uv_fs_req_cleanup(&rename_req); - r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDONLY | add_flags, 0, + r = uv_fs_open(NULL, &open_req1, "test_file2", UV_FS_O_RDONLY | add_flags, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); @@ -1071,7 +1077,8 @@ static void fs_file_write_null_buffer(int add_flags) { loop = uv_default_loop(); r = uv_fs_open(NULL, &open_req1, "test_file", - O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); + UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -1116,7 +1123,8 @@ TEST_IMPL(fs_async_dir) { ASSERT_EQ(1, mkdir_cb_count); /* Create 2 files synchronously. */ - r = uv_fs_open(NULL, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT, + r = uv_fs_open(NULL, &open_req1, "test_dir/file1", + UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); uv_fs_req_cleanup(&open_req1); @@ -1124,7 +1132,8 @@ TEST_IMPL(fs_async_dir) { ASSERT_OK(r); uv_fs_req_cleanup(&close_req); - r = uv_fs_open(NULL, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT, + r = uv_fs_open(NULL, &open_req1, "test_dir/file2", + UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); uv_fs_req_cleanup(&open_req1); @@ -1193,7 +1202,7 @@ TEST_IMPL(fs_async_dir) { } -static int test_sendfile(void (*setup)(int), uv_fs_cb cb, off_t expected_size) { +static int test_sendfile(void (*setup)(int), uv_fs_cb cb, size_t expected_size) { int f, r; struct stat s1, s2; uv_fs_t req; @@ -1205,7 +1214,7 @@ static int test_sendfile(void (*setup)(int), uv_fs_cb cb, off_t expected_size) { unlink("test_file"); unlink("test_file2"); - f = open("test_file", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR); + f = open("test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR); ASSERT_NE(f, -1); if (setup != NULL) @@ -1215,12 +1224,12 @@ static int test_sendfile(void (*setup)(int), uv_fs_cb cb, off_t expected_size) { ASSERT_OK(r); /* Test starts here. */ - r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDWR, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); - r = uv_fs_open(NULL, &open_req2, "test_file2", O_WRONLY | O_CREAT, + r = uv_fs_open(NULL, &open_req2, "test_file2", UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req2.result, 0); @@ -1248,7 +1257,7 @@ static int test_sendfile(void (*setup)(int), uv_fs_cb cb, off_t expected_size) { if (expected_size > 0) { ASSERT_UINT64_EQ(s1.st_size, s2.st_size + 1); - r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &open_req1, "test_file2", UV_FS_O_RDWR, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -1364,7 +1373,7 @@ TEST_IMPL(fs_mkstemp) { uv_fs_close(NULL, &req, mkstemp_req2.result, NULL); uv_fs_req_cleanup(&req); - fd = uv_fs_open(NULL, &req, mkstemp_req1.path , O_RDONLY, 0, NULL); + fd = uv_fs_open(NULL, &req, mkstemp_req1.path, UV_FS_O_RDONLY, 0, NULL); ASSERT_GE(fd, 0); uv_fs_req_cleanup(&req); @@ -1410,7 +1419,7 @@ TEST_IMPL(fs_fstat) { loop = uv_default_loop(); - r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, + r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); @@ -1617,7 +1626,7 @@ TEST_IMPL(fs_access) { access_cb_count = 0; /* reset for the next test */ /* Create file */ - r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, + r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); @@ -1678,7 +1687,7 @@ TEST_IMPL(fs_chmod) { loop = uv_default_loop(); - r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, + r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); @@ -1777,9 +1786,7 @@ TEST_IMPL(fs_unlink_readonly) { loop = uv_default_loop(); r = uv_fs_open(NULL, - &req, - "test_file", - O_RDWR | O_CREAT, + &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -1836,9 +1843,7 @@ TEST_IMPL(fs_unlink_archive_readonly) { loop = uv_default_loop(); r = uv_fs_open(NULL, - &req, - "test_file", - O_RDWR | O_CREAT, + &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -1894,7 +1899,7 @@ TEST_IMPL(fs_chown) { loop = uv_default_loop(); - r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, + r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); @@ -1989,7 +1994,7 @@ TEST_IMPL(fs_link) { loop = uv_default_loop(); - r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, + r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); @@ -2010,7 +2015,7 @@ TEST_IMPL(fs_link) { ASSERT_OK(req.result); uv_fs_req_cleanup(&req); - r = uv_fs_open(NULL, &req, "test_file_link", O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &req, "test_file_link", UV_FS_O_RDWR, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); link = req.result; @@ -2031,7 +2036,7 @@ TEST_IMPL(fs_link) { uv_run(loop, UV_RUN_DEFAULT); ASSERT_EQ(1, link_cb_count); - r = uv_fs_open(NULL, &req, "test_file_link2", O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &req, "test_file_link2", UV_FS_O_RDWR, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); link = req.result; @@ -2090,7 +2095,7 @@ TEST_IMPL(fs_readlink) { /* Setup */ /* Create a non-symlink file */ - r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, + r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); @@ -2162,7 +2167,7 @@ TEST_IMPL(fs_symlink) { loop = uv_default_loop(); - r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, + r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); @@ -2200,7 +2205,7 @@ TEST_IMPL(fs_symlink) { ASSERT_OK(req.result); uv_fs_req_cleanup(&req); - r = uv_fs_open(NULL, &req, "test_file_symlink", O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &req, "test_file_symlink", UV_FS_O_RDWR, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); link = req.result; @@ -2236,7 +2241,7 @@ TEST_IMPL(fs_symlink) { r = uv_fs_realpath(NULL, &req, "test_file_symlink_symlink", NULL); ASSERT_OK(r); #ifdef _WIN32 - ASSERT_OK(stricmp(req.ptr, test_file_abs_buf)); + ASSERT_OK(_stricmp(req.ptr, test_file_abs_buf)); #else ASSERT_OK(strcmp(req.ptr, test_file_abs_buf)); #endif @@ -2253,7 +2258,7 @@ TEST_IMPL(fs_symlink) { uv_run(loop, UV_RUN_DEFAULT); ASSERT_EQ(1, symlink_cb_count); - r = uv_fs_open(NULL, &req, "test_file_symlink2", O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &req, "test_file_symlink2", UV_FS_O_RDWR, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); link = req.result; @@ -2386,13 +2391,14 @@ int test_symlink_dir_impl(int type) { ASSERT_OK(r); #ifdef _WIN32 ASSERT_EQ(strlen(req.ptr), test_dir_abs_size - 5); - ASSERT_OK(strnicmp(req.ptr, test_dir + 4, test_dir_abs_size - 5)); + ASSERT_OK(_strnicmp(req.ptr, test_dir + 4, test_dir_abs_size - 5)); #else ASSERT_OK(strcmp(req.ptr, test_dir_abs_buf)); #endif uv_fs_req_cleanup(&req); - r = uv_fs_open(NULL, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT, + r = uv_fs_open(NULL, &open_req1, "test_dir/file1", + UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); uv_fs_req_cleanup(&open_req1); @@ -2400,7 +2406,8 @@ int test_symlink_dir_impl(int type) { ASSERT_OK(r); uv_fs_req_cleanup(&close_req); - r = uv_fs_open(NULL, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT, + r = uv_fs_open(NULL, &open_req1, "test_dir/file2", + UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); uv_fs_req_cleanup(&open_req1); @@ -2622,7 +2629,9 @@ TEST_IMPL(fs_utime) { /* Setup. */ loop = uv_default_loop(); unlink(path); - r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); + r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR | UV_FS_O_CREAT, + S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); uv_fs_req_cleanup(&req); @@ -2666,7 +2675,9 @@ TEST_IMPL(fs_utime_round) { loop = uv_default_loop(); unlink(path); - r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); + r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR | UV_FS_O_CREAT, + S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); uv_fs_req_cleanup(&req); @@ -2743,7 +2754,9 @@ TEST_IMPL(fs_futime) { /* Setup. */ loop = uv_default_loop(); unlink(path); - r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); + r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR | UV_FS_O_CREAT, + S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); uv_fs_req_cleanup(&req); @@ -2751,7 +2764,7 @@ TEST_IMPL(fs_futime) { atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */ - r = uv_fs_open(NULL, &req, path, O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); file = req.result; /* FIXME probably not how it's supposed to be used */ @@ -2803,7 +2816,9 @@ TEST_IMPL(fs_lutime) { /* Setup */ loop = uv_default_loop(); unlink(path); - r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); + r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR | UV_FS_O_CREAT, + S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); uv_fs_req_cleanup(&req); @@ -2999,7 +3014,7 @@ TEST_IMPL(fs_open_dir) { path = "."; loop = uv_default_loop(); - r = uv_fs_open(NULL, &req, path, O_RDONLY, 0, NULL); + r = uv_fs_open(NULL, &req, path, UV_FS_O_RDONLY, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); ASSERT_NULL(req.ptr); @@ -3009,7 +3024,7 @@ TEST_IMPL(fs_open_dir) { r = uv_fs_close(NULL, &req, file, NULL); ASSERT_OK(r); - r = uv_fs_open(loop, &req, path, O_RDONLY, 0, open_cb_simple); + r = uv_fs_open(loop, &req, path, UV_FS_O_RDONLY, 0, open_cb_simple); ASSERT_OK(r); ASSERT_OK(open_cb_count); @@ -3030,7 +3045,8 @@ static void fs_file_open_append(int add_flags) { loop = uv_default_loop(); r = uv_fs_open(NULL, &open_req1, "test_file", - O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); + UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -3047,7 +3063,7 @@ static void fs_file_open_append(int add_flags) { uv_fs_req_cleanup(&close_req); r = uv_fs_open(NULL, &open_req1, "test_file", - O_RDWR | O_APPEND | add_flags, 0, NULL); + UV_FS_O_RDWR | UV_FS_O_APPEND | add_flags, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -3063,7 +3079,7 @@ static void fs_file_open_append(int add_flags) { ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); - r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, + r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY | add_flags, S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); @@ -3105,7 +3121,7 @@ TEST_IMPL(fs_rename_to_existing_file) { loop = uv_default_loop(); - r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT, + r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); @@ -3122,7 +3138,7 @@ TEST_IMPL(fs_rename_to_existing_file) { ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); - r = uv_fs_open(NULL, &open_req1, "test_file2", O_WRONLY | O_CREAT, + r = uv_fs_open(NULL, &open_req1, "test_file2", UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); @@ -3138,7 +3154,7 @@ TEST_IMPL(fs_rename_to_existing_file) { ASSERT_OK(rename_req.result); uv_fs_req_cleanup(&rename_req); - r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDONLY, 0, NULL); + r = uv_fs_open(NULL, &open_req1, "test_file2", UV_FS_O_RDONLY, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -3171,7 +3187,7 @@ static void fs_read_bufs(int add_flags) { ASSERT_LE(0, uv_fs_open(NULL, &open_req1, "test/fixtures/lorem_ipsum.txt", - O_RDONLY | add_flags, 0, NULL)); + UV_FS_O_RDONLY | add_flags, 0, NULL)); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -3235,7 +3251,8 @@ static void fs_read_file_eof(int add_flags) { loop = uv_default_loop(); r = uv_fs_open(NULL, &open_req1, "test_file", - O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); + UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -3251,7 +3268,7 @@ static void fs_read_file_eof(int add_flags) { ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); - r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, 0, + r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY | add_flags, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); @@ -3299,7 +3316,8 @@ static void fs_write_multiple_bufs(int add_flags) { loop = uv_default_loop(); r = uv_fs_open(NULL, &open_req1, "test_file", - O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); + UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -3316,7 +3334,7 @@ static void fs_write_multiple_bufs(int add_flags) { ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); - r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, 0, + r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY | add_flags, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); @@ -3405,7 +3423,7 @@ static void fs_write_alotof_bufs(int add_flags) { r = uv_fs_open(NULL, &open_req1, "test_file", - O_RDWR | O_CREAT | add_flags, + UV_FS_O_RDWR | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -3439,7 +3457,7 @@ static void fs_write_alotof_bufs(int add_flags) { ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); - r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, 0, + r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY | add_flags, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); @@ -3518,7 +3536,7 @@ static void fs_write_alotof_bufs_with_offset(int add_flags) { r = uv_fs_open(NULL, &open_req1, "test_file", - O_RDWR | O_CREAT | add_flags, + UV_FS_O_RDWR | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -3904,9 +3922,7 @@ TEST_IMPL(get_osfhandle_valid_handle) { loop = uv_default_loop(); r = uv_fs_open(NULL, - &open_req1, - "test_file", - O_RDWR | O_CREAT, + &open_req1, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -3945,7 +3961,7 @@ TEST_IMPL(open_osfhandle_valid_handle) { r = uv_fs_open(NULL, &open_req1, "test_file", - O_RDWR | O_CREAT, + UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -3986,9 +4002,7 @@ TEST_IMPL(fs_file_pos_after_op_with_offset) { loop = uv_default_loop(); r = uv_fs_open(loop, - &open_req1, - "test_file", - O_RDWR | O_CREAT, + &open_req1, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GT(r, 0); @@ -4060,7 +4074,7 @@ static void fs_file_pos_close_check(const char *contents, int size) { uv_fs_req_cleanup(&close_req); /* Confirm file contents */ - r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY, 0, NULL); + r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -4088,7 +4102,7 @@ static void fs_file_pos_write(int add_flags) { r = uv_fs_open(NULL, &open_req1, "test_file", - O_TRUNC | O_CREAT | O_RDWR | add_flags, + UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_RDWR | add_flags, S_IWUSR | S_IRUSR, NULL); ASSERT_GT(r, 0); @@ -4126,7 +4140,7 @@ static void fs_file_pos_append(int add_flags) { r = uv_fs_open(NULL, &open_req1, "test_file", - O_APPEND | O_CREAT | O_RDWR | add_flags, + UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_RDWR | add_flags, S_IWUSR | S_IRUSR, NULL); ASSERT_GT(r, 0); @@ -4273,7 +4287,7 @@ TEST_IMPL(fs_exclusive_sharing_mode) { r = uv_fs_open(NULL, &open_req1, "test_file", - O_RDWR | O_CREAT | UV_FS_O_EXLOCK, + UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_EXLOCK, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -4282,8 +4296,7 @@ TEST_IMPL(fs_exclusive_sharing_mode) { r = uv_fs_open(NULL, &open_req2, - "test_file", - O_RDONLY | UV_FS_O_EXLOCK, + "test_file", UV_FS_O_RDONLY | UV_FS_O_EXLOCK, S_IWUSR | S_IRUSR, NULL); ASSERT_LT(r, 0); @@ -4297,8 +4310,7 @@ TEST_IMPL(fs_exclusive_sharing_mode) { r = uv_fs_open(NULL, &open_req2, - "test_file", - O_RDONLY | UV_FS_O_EXLOCK, + "test_file", UV_FS_O_RDONLY | UV_FS_O_EXLOCK, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -4405,7 +4417,7 @@ TEST_IMPL(fs_open_readonly_acl) { r = uv_fs_open(loop, &open_req1, "test_file_icacls", - O_RDONLY | O_CREAT, + UV_FS_O_RDONLY | UV_FS_O_CREAT, S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -4428,7 +4440,8 @@ TEST_IMPL(fs_open_readonly_acl) { } /* Try opening the file */ - r = uv_fs_open(NULL, &open_req1, "test_file_icacls", O_RDONLY, 0, NULL); + r = uv_fs_open(NULL, &open_req1, "test_file_icacls", UV_FS_O_RDONLY, 0, + NULL); if (r < 0) { goto acl_cleanup; } @@ -4461,9 +4474,7 @@ TEST_IMPL(fs_fchmod_archive_readonly) { /* Setup*/ unlink("test_file"); r = uv_fs_open(NULL, - &req, - "test_file", - O_WRONLY | O_CREAT, + &req, "test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -4478,7 +4489,7 @@ TEST_IMPL(fs_fchmod_archive_readonly) { ASSERT(r); check_permission("test_file", 0400); /* Try fchmod */ - r = uv_fs_open(NULL, &req, "test_file", O_RDONLY, 0, NULL); + r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDONLY, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); file = req.result; diff --git a/test/test-getters-setters.c b/test/test-getters-setters.c index e4c6717d..3b9e89e1 100644 --- a/test/test-getters-setters.c +++ b/test/test-getters-setters.c @@ -24,6 +24,10 @@ #include #include +#ifdef _WIN32 +# define S_IFDIR _S_IFDIR +#endif + int cookie1; int cookie2; int cookie3; diff --git a/test/test-metrics.c b/test/test-metrics.c index c7c73aa5..361fcef5 100644 --- a/test/test-metrics.c +++ b/test/test-metrics.c @@ -217,7 +217,7 @@ static void prepare_cb(uv_prepare_t* handle) { ASSERT_OK(uv_fs_open(uv_default_loop(), &fs_reqs.open_req, "test_file", - O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR, + UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IRUSR | S_IWUSR, create_cb)); } @@ -329,9 +329,7 @@ TEST_IMPL(metrics_pool_events) { pool_events_counter = 0; fd = uv_fs_open(NULL, - &open_req, - "test_file", - O_WRONLY | O_CREAT, + &open_req, "test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IRUSR | S_IWUSR, NULL); ASSERT_GT(fd, 0); diff --git a/test/test-poll.c b/test/test-poll.c index f5a30e9a..fcd644f2 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -23,6 +23,7 @@ #ifdef _WIN32 # include +# define close _close #else # include # include @@ -638,9 +639,9 @@ TEST_IMPL(poll_bad_fdtype) { int fd; #if defined(_WIN32) - fd = open("test/fixtures/empty_file", O_RDONLY); + fd = _open("test/fixtures/empty_file", UV_FS_O_RDONLY); #else - fd = open(".", O_RDONLY); + fd = open(".", UV_FS_O_RDONLY); #endif ASSERT_NE(fd, -1); ASSERT_NE(0, uv_poll_init(uv_default_loop(), &poll_handle, fd)); diff --git a/test/test-spawn.c b/test/test-spawn.c index bbb7cb49..33552717 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -32,6 +32,9 @@ # include # include typedef BOOL (WINAPI *sCompareObjectHandles)(_In_ HANDLE, _In_ HANDLE); +# define unlink _unlink +# define putenv _putenv +# define close _close #else # include # include @@ -322,7 +325,7 @@ TEST_IMPL(spawn_stdout_to_file) { init_process_options("spawn_helper2", exit_cb); - r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR, + r = uv_fs_open(NULL, &fs_req, "stdout_file", UV_FS_O_CREAT | UV_FS_O_RDWR, S_IRUSR | S_IWUSR, NULL); ASSERT_NE(r, -1); uv_fs_req_cleanup(&fs_req); @@ -376,7 +379,7 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file) { init_process_options("spawn_helper6", exit_cb); - r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR, + r = uv_fs_open(NULL, &fs_req, "stdout_file", UV_FS_O_CREAT | UV_FS_O_RDWR, S_IRUSR | S_IWUSR, NULL); ASSERT_NE(r, -1); uv_fs_req_cleanup(&fs_req); @@ -1621,7 +1624,7 @@ TEST_IMPL(spawn_fs_open) { const char dev_null[] = "/dev/null"; #endif - r = uv_fs_open(NULL, &fs_req, dev_null, O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &fs_req, dev_null, UV_FS_O_RDWR, 0, NULL); ASSERT_NE(r, -1); fd = uv_get_osfhandle((uv_file) fs_req.result); uv_fs_req_cleanup(&fs_req); diff --git a/test/test-threadpool-cancel.c b/test/test-threadpool-cancel.c index b758ac4f..544fbbc3 100644 --- a/test/test-threadpool-cancel.c +++ b/test/test-threadpool-cancel.c @@ -22,6 +22,10 @@ #include "uv.h" #include "task.h" +#ifdef _WIN32 +# define putenv _putenv +#endif + #define INIT_CANCEL_INFO(ci, what) \ do { \ (ci)->reqs = (what); \ From 51a22f60d6f41a92b68def1f048e53b593037d11 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov Date: Fri, 22 Dec 2023 08:40:50 -0300 Subject: [PATCH 27/48] unix,win: fix busy loop with zero timeout timers (#4250) Calling `uv_timer_start(h, cb, 0, 0)` from a timer callback resulted in the timer running immediately because it was inserted at the front of the timer heap. If the callback did that every time, libuv would effectively busy-loop in `uv__run_timers()` and never make forward progress. Work around that by collecting all expired timers into a queue and only running their callback afterwards. Fixes: https://github.com/libuv/libuv/issues/4245 Co-authored-by: Ben Noordhuis --- include/uv/unix.h | 5 ++++- include/uv/win.h | 5 ++++- src/timer.c | 45 +++++++++++++++++++++++++++++++-------------- test/test-list.h | 2 ++ test/test-timer.c | 26 ++++++++++++++++++++++++++ 5 files changed, 67 insertions(+), 16 deletions(-) diff --git a/include/uv/unix.h b/include/uv/unix.h index 09f88a56..538f98b6 100644 --- a/include/uv/unix.h +++ b/include/uv/unix.h @@ -328,7 +328,10 @@ typedef struct { #define UV_TIMER_PRIVATE_FIELDS \ uv_timer_cb timer_cb; \ - void* heap_node[3]; \ + union { \ + void* heap[3]; \ + struct uv__queue queue; \ + } node; \ uint64_t timeout; \ uint64_t repeat; \ uint64_t start_id; diff --git a/include/uv/win.h b/include/uv/win.h index 6f8c4729..ad7b3e9a 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -550,7 +550,10 @@ typedef struct { unsigned char events; #define UV_TIMER_PRIVATE_FIELDS \ - void* heap_node[3]; \ + union { \ + void* heap[3]; \ + struct uv__queue queue; \ + } node; \ int unused; \ uint64_t timeout; \ uint64_t repeat; \ diff --git a/src/timer.c b/src/timer.c index bc680e71..b57d6427 100644 --- a/src/timer.c +++ b/src/timer.c @@ -40,8 +40,8 @@ static int timer_less_than(const struct heap_node* ha, const uv_timer_t* a; const uv_timer_t* b; - a = container_of(ha, uv_timer_t, heap_node); - b = container_of(hb, uv_timer_t, heap_node); + a = container_of(ha, uv_timer_t, node.heap); + b = container_of(hb, uv_timer_t, node.heap); if (a->timeout < b->timeout) return 1; @@ -60,6 +60,7 @@ int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { handle->timer_cb = NULL; handle->timeout = 0; handle->repeat = 0; + uv__queue_init(&handle->node.queue); return 0; } @@ -73,8 +74,7 @@ int uv_timer_start(uv_timer_t* handle, if (uv__is_closing(handle) || cb == NULL) return UV_EINVAL; - if (uv__is_active(handle)) - uv_timer_stop(handle); + uv_timer_stop(handle); clamped_timeout = handle->loop->time + timeout; if (clamped_timeout < timeout) @@ -87,23 +87,27 @@ int uv_timer_start(uv_timer_t* handle, handle->start_id = handle->loop->timer_counter++; heap_insert(timer_heap(handle->loop), - (struct heap_node*) &handle->heap_node, + (struct heap_node*) &handle->node.heap, timer_less_than); uv__handle_start(handle); return 0; } - -int uv_timer_stop(uv_timer_t* handle) { - if (!uv__is_active(handle)) - return 0; - +static void timer_stop(uv_timer_t* handle) { heap_remove(timer_heap(handle->loop), - (struct heap_node*) &handle->heap_node, + (struct heap_node*) &handle->node.heap, timer_less_than); uv__handle_stop(handle); + uv__queue_init(&handle->node.queue); +} + +int uv_timer_stop(uv_timer_t* handle) { + if (uv__is_active(handle)) + timer_stop(handle); + else + uv__queue_remove(&handle->node.queue); return 0; } @@ -148,7 +152,7 @@ int uv__next_timeout(const uv_loop_t* loop) { if (heap_node == NULL) return -1; /* block indefinitely */ - handle = container_of(heap_node, uv_timer_t, heap_node); + handle = container_of(heap_node, uv_timer_t, node.heap); if (handle->timeout <= loop->time) return 0; @@ -163,17 +167,30 @@ int uv__next_timeout(const uv_loop_t* loop) { void uv__run_timers(uv_loop_t* loop) { struct heap_node* heap_node; uv_timer_t* handle; + struct uv__queue* queue_node; + struct uv__queue ready_queue; + + uv__queue_init(&ready_queue); for (;;) { heap_node = heap_min(timer_heap(loop)); if (heap_node == NULL) break; - handle = container_of(heap_node, uv_timer_t, heap_node); + handle = container_of(heap_node, uv_timer_t, node.heap); if (handle->timeout > loop->time) break; - uv_timer_stop(handle); + timer_stop(handle); + uv__queue_insert_tail(&ready_queue, &handle->node.queue); + } + + while (!uv__queue_empty(&ready_queue)) { + queue_node = uv__queue_head(&ready_queue); + uv__queue_remove(queue_node); + uv__queue_init(queue_node); + handle = container_of(queue_node, uv_timer_t, node.queue); + uv_timer_again(handle); handle->timer_cb(handle); } diff --git a/test/test-list.h b/test/test-list.h index f042bc29..e97b941f 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -227,6 +227,7 @@ TEST_DECLARE (timer_init) TEST_DECLARE (timer_again) TEST_DECLARE (timer_start_twice) TEST_DECLARE (timer_order) +TEST_DECLARE (timer_zero_timeout) TEST_DECLARE (timer_huge_timeout) TEST_DECLARE (timer_huge_repeat) TEST_DECLARE (timer_run_once) @@ -849,6 +850,7 @@ TASK_LIST_START TEST_ENTRY (timer_again) TEST_ENTRY (timer_start_twice) TEST_ENTRY (timer_order) + TEST_ENTRY (timer_zero_timeout) TEST_ENTRY (timer_huge_timeout) TEST_ENTRY (timer_huge_repeat) TEST_ENTRY (timer_run_once) diff --git a/test/test-timer.c b/test/test-timer.c index d889e707..641d3a90 100644 --- a/test/test-timer.c +++ b/test/test-timer.c @@ -31,6 +31,7 @@ static int repeat_cb_called = 0; static int repeat_close_cb_called = 0; static int order_cb_called = 0; static int timer_check_double_call_called = 0; +static int zero_timeout_cb_calls = 0; static uint64_t start_time; static uv_timer_t tiny_timer; static uv_timer_t huge_timer1; @@ -242,6 +243,31 @@ TEST_IMPL(timer_order) { } +static void zero_timeout_cb(uv_timer_t* handle) { + ASSERT_OK(uv_timer_start(handle, zero_timeout_cb, 0, 0)); + uv_stop(handle->loop); + zero_timeout_cb_calls++; +} + + +TEST_IMPL(timer_zero_timeout) { + uv_timer_t timer; + uv_loop_t* loop; + + loop = uv_default_loop(); + ASSERT_OK(uv_timer_init(loop, &timer)); + ASSERT_OK(uv_timer_start(&timer, zero_timeout_cb, 0, 0)); + ASSERT_EQ(1, uv_run(loop, UV_RUN_DEFAULT)); /* because of uv_stop() */ + ASSERT_EQ(1, zero_timeout_cb_calls); + uv_close((uv_handle_t*) &timer, NULL); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(1, zero_timeout_cb_calls); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} + + static void tiny_timer_cb(uv_timer_t* handle) { ASSERT_PTR_EQ(handle, &tiny_timer); uv_close((uv_handle_t*) &tiny_timer, NULL); From 8861a97efac54a9ab17e8174cc826a0ca1804e41 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Fri, 22 Dec 2023 23:58:49 +0000 Subject: [PATCH 28/48] aix,ibmi: use uv_interface_addresses instead of getifaddrs (#4222) AIX and IBM i don't have getifaddrs but we do have code in `uv_interface_addresses` to get the interface addresses. Refs: https://github.com/libuv/libuv/issues/4117 --- src/unix/tcp.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index f455c53f..a4ef71b5 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -220,14 +220,32 @@ static int uv__is_ipv6_link_local(const struct sockaddr* addr) { static int uv__ipv6_link_local_scope_id(void) { -/* disable link local on AIX & PASE for now */ -#if defined(_AIX) - return 0; -#else struct sockaddr_in6* a6; + int rv; +#if defined(_AIX) + /* AIX & IBM i do not have ifaddrs + * so fallback to use uv_interface_addresses */ + uv_interface_address_t* interfaces; + uv_interface_address_t* ifa; + int count, i; + + if (uv_interface_addresses(&interfaces, &count)) + return 0; + + rv = 0; + + for (ifa = interfaces; ifa != &interfaces[count]; ifa++) { + if (uv__is_ipv6_link_local((struct sockaddr*) &ifa->address)) { + rv = ifa->address.address6.sin6_scope_id; + break; + } + } + + uv_free_interface_addresses(interfaces, count); + +#else struct ifaddrs* ifa; struct ifaddrs* p; - int rv; if (getifaddrs(&ifa)) return 0; @@ -244,8 +262,9 @@ static int uv__ipv6_link_local_scope_id(void) { } freeifaddrs(ifa); +#endif /* defined(_AIX) */ + return rv; -#endif } From 1dd0ab13154ccad38839807fe4909469f7164e25 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Mon, 25 Dec 2023 23:35:14 +0100 Subject: [PATCH 29/48] linux: fix bind/connect for abstract sockets (#4266) The `\0` character has no special significance in abstract sockets, so the addrlen field in both `bind()` and `connect()` should take that into account. --- src/unix/pipe.c | 17 +++++++++++++---- test/test-pipe-getsockname.c | 7 ++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index bb2806f5..fca36442 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -66,6 +66,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, char* pipe_fname; int sockfd; int err; + socklen_t addrlen; pipe_fname = NULL; @@ -100,12 +101,15 @@ int uv_pipe_bind2(uv_pipe_t* handle, * We unlink the file later but abstract sockets disappear * automatically since they're not real file system entities. */ - if (*name != '\0') { + if (*name == '\0') { + addrlen = offsetof(struct sockaddr_un, sun_path) + namelen; + } else { pipe_fname = uv__malloc(namelen + 1); if (pipe_fname == NULL) return UV_ENOMEM; memcpy(pipe_fname, name, namelen); pipe_fname[namelen] = '\0'; + addrlen = sizeof saddr; } err = uv__socket(AF_UNIX, SOCK_STREAM, 0); @@ -117,7 +121,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, memcpy(&saddr.sun_path, name, namelen); saddr.sun_family = AF_UNIX; - if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) { + if (bind(sockfd, (struct sockaddr*)&saddr, addrlen)) { err = UV__ERR(errno); /* Convert ENOENT to EACCES for compatibility with Windows. */ if (err == UV_ENOENT) @@ -251,6 +255,7 @@ int uv_pipe_connect2(uv_connect_t* req, int new_sock; int err; int r; + socklen_t addrlen; if (flags & ~UV_PIPE_NO_TRUNCATE) return UV_EINVAL; @@ -285,9 +290,13 @@ int uv_pipe_connect2(uv_connect_t* req, memcpy(&saddr.sun_path, name, namelen); saddr.sun_family = AF_UNIX; + if (*name == '\0') + addrlen = offsetof(struct sockaddr_un, sun_path) + namelen; + else + addrlen = sizeof saddr; + do { - r = connect(uv__stream_fd(handle), - (struct sockaddr*)&saddr, sizeof saddr); + r = connect(uv__stream_fd(handle), (struct sockaddr*)&saddr, addrlen); } while (r == -1 && errno == EINTR); diff --git a/test/test-pipe-getsockname.c b/test/test-pipe-getsockname.c index bac723c6..d76b6ad4 100644 --- a/test/test-pipe-getsockname.c +++ b/test/test-pipe-getsockname.c @@ -60,8 +60,8 @@ static void pipe_client_connect_cb(uv_connect_t* req, int status) { if (*buf == '\0') { /* Linux abstract socket. */ const char expected[] = "\0" TEST_PIPENAME; - ASSERT_GE(len, sizeof(expected)); - ASSERT_MEM_EQ(buf, expected, sizeof(expected)); + ASSERT_EQ(len, sizeof(expected) - 1); + ASSERT_MEM_EQ(buf, expected, len); } else { ASSERT_NE(0, buf[len - 1]); ASSERT_MEM_EQ(buf, TEST_PIPENAME, len); @@ -191,7 +191,8 @@ TEST_IMPL(pipe_getsockname_abstract) { ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_server, 0)); ASSERT_OK(uv_pipe_bind2(&pipe_server, name, sizeof(name) - 1, 0)); ASSERT_OK(uv_pipe_getsockname(&pipe_server, buf, &buflen)); - ASSERT_MEM_EQ(name, buf, sizeof(name)); + ASSERT_UINT64_EQ(sizeof(name) - 1, buflen); + ASSERT_MEM_EQ(name, buf, buflen); ASSERT_OK(uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb)); From 64bd28f5ba86a9c85fcbcd10a52811369925fc69 Mon Sep 17 00:00:00 2001 From: Trevor Flynn Date: Fri, 5 Jan 2024 00:34:33 -0900 Subject: [PATCH 30/48] win: replace c99 comments with c89 comments (#4270) --- include/uv/win.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/uv/win.h b/include/uv/win.h index ad7b3e9a..f4adaa21 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -45,7 +45,7 @@ typedef struct pollfd { #endif #include -// Disable the typedef in mstcpip.h of MinGW. +/* Disable the typedef in mstcpip.h of MinGW. */ #define _TCP_INITIAL_RTO_PARAMETERS _TCP_INITIAL_RTO_PARAMETERS__AVOID #define TCP_INITIAL_RTO_PARAMETERS TCP_INITIAL_RTO_PARAMETERS__AVOID #define PTCP_INITIAL_RTO_PARAMETERS PTCP_INITIAL_RTO_PARAMETERS__AVOID @@ -70,7 +70,7 @@ typedef struct pollfd { # define S_IFLNK 0xA000 #endif -// Define missing in Windows Kit Include\{VERSION}\ucrt\sys\stat.h +/* Define missing in Windows Kit Include\{VERSION}\ucrt\sys\stat.h */ #if defined(_CRT_INTERNAL_NONSTDC_NAMES) && _CRT_INTERNAL_NONSTDC_NAMES && !defined(S_IFIFO) # define S_IFIFO _S_IFIFO #endif From e72a91e0636f0dc68ee8518786d8776270cd1dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9?= Date: Fri, 5 Jan 2024 04:38:15 -0500 Subject: [PATCH 31/48] build: add .cache clangd folder to .gitignore (#4257) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The clangd index, before creating the `compile_commands.json` file will create the indexes under a `.cache` folder. This does not need to be tracked by the repo. Signed-off-by: Juan José Arboleda --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d184d21c..6d396efb 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ *.VC.db *.VC.opendb core +.cache vgcore.* .buildstamp .dirstamp From a9381cdb03f756cc42307584aeec084fd31fee3d Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Sat, 6 Jan 2024 17:46:47 +0800 Subject: [PATCH 32/48] unix: support full TCP keep-alive on Solaris (#4272) Solaris claimed it supported the TCP-Alives mechanism, but TCP_KEEPIDLE, TCP_KEEPINTVL, and TCP_KEEPCNT were not available on Solaris until the latest version 11.4. Therefore, we need to simulate the TCP-Alives mechanism on other platforms via TCP_KEEPALIVE_THRESHOLD + TCP_KEEPALIVE_ABORT_THRESHOLD. --- src/unix/tcp.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 6 deletions(-) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index a4ef71b5..31ecf5bd 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -453,26 +453,89 @@ int uv__tcp_nodelay(int fd, int on) { int uv__tcp_keepalive(int fd, int on, unsigned int delay) { + int idle; int intvl; int cnt; + (void) &idle; (void) &intvl; (void) &cnt; - + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on))) return UV__ERR(errno); if (!on) return 0; + if (delay == 0) + return -1; + + /* The implementation of TCP keep-alive on Solaris/SmartOS is a bit unusual + * compared to other Unix-like systems. + * Thus, we need to specialize it on Solaris. */ +#ifdef __sun + /* There are two keep-alive mechanisms on Solaris: + * - By default, the first keep-alive probe is sent out after a TCP connection is idle for two hours. + * If the peer does not respond to the probe within eight minutes, the TCP connection is aborted. + * You can alter the interval for sending out the first probe using the socket option TCP_KEEPALIVE_THRESHOLD + * in milliseconds or TCP_KEEPIDLE in seconds. + * The system default is controlled by the TCP ndd parameter tcp_keepalive_interval. The minimum value is ten seconds. + * The maximum is ten days, while the default is two hours. If you receive no response to the probe, + * you can use the TCP_KEEPALIVE_ABORT_THRESHOLD socket option to change the time threshold for aborting a TCP connection. + * The option value is an unsigned integer in milliseconds. The value zero indicates that TCP should never time out and + * abort the connection when probing. The system default is controlled by the TCP ndd parameter tcp_keepalive_abort_interval. + * The default is eight minutes. + * + * - The second implementation is activated if socket option TCP_KEEPINTVL and/or TCP_KEEPCNT are set. + * The time between each consequent probes is set by TCP_KEEPINTVL in seconds. + * The minimum value is ten seconds. The maximum is ten days, while the default is two hours. + * The TCP connection will be aborted after certain amount of probes, which is set by TCP_KEEPCNT, without receiving response. + */ + + idle = delay; + /* Kernel expects at least 10 seconds. */ + if (idle < 10) + idle = 10; + /* Kernel expects at most 10 days. */ + if (idle > 10*24*60*60) + idle = 10*24*60*60; + + /* `TCP_KEEPIDLE`, `TCP_KEEPINTVL`, and `TCP_KEEPCNT` were not available on Solaris + * until version 11.4, but let's take a chance here. */ +#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT) + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle))) + return UV__ERR(errno); + intvl = idle/3; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl))) + return UV__ERR(errno); + cnt = 3; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt))) + return UV__ERR(errno); + return 0; +#endif + + /* Fall back to the first implementation of tcp-alive mechanism for older Solaris, + * simulate the tcp-alive mechanism on other platforms via `TCP_KEEPALIVE_THRESHOLD` + `TCP_KEEPALIVE_ABORT_THRESHOLD`. + */ + idle *= 1000; /* kernel expects milliseconds */ + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, &idle, sizeof(idle))) + return UV__ERR(errno); + + /* Note that the consequent probes will not be sent at equal intervals on Solaris, + * but will be sent using the exponential backoff algorithm. */ + intvl = idle/3; + cnt = 3; + int time_to_abort = intvl * cnt; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, &time_to_abort, sizeof(time_to_abort))) + return UV__ERR(errno); + + return 0; +#endif + #ifdef TCP_KEEPIDLE if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) return UV__ERR(errno); -/* Solaris/SmartOS, if you don't support keep-alive, - * then don't advertise it in your system headers... - */ -/* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */ -#elif defined(TCP_KEEPALIVE) && !defined(__sun) +#elif defined(TCP_KEEPALIVE) if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay))) return UV__ERR(errno); #endif From 7d092913b37f6211375e0c16fff19e4f9a011b2b Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sun, 7 Jan 2024 11:58:32 +0000 Subject: [PATCH 33/48] freebsd: fix F_KINFO file path handling (#4256) The new F_KINFO flag does not seem to work with directories nor with deleted entries. Fixes: https://github.com/libuv/libuv/issues/4255 --- src/unix/kqueue.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 94ace586..d7aa60e7 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -488,11 +488,15 @@ static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) { * the struct's kf_structsize must be initialised beforehand * whether with the KINFO_FILE_SIZE constant or this way. */ + struct stat statbuf; struct kinfo_file kf; - kf.kf_structsize = sizeof(kf); - if (fcntl(handle->event_watcher.fd, F_KINFO, &kf) == 0) - path = uv__basename_r(kf.kf_path); + if (handle->event_watcher.fd != -1 && + (!uv__fstat(handle->event_watcher.fd, &statbuf) && !(statbuf.st_mode & S_IFDIR))) { + kf.kf_structsize = KINFO_FILE_SIZE; + if (fcntl(handle->event_watcher.fd, F_KINFO, &kf) == 0) + path = uv__basename_r(kf.kf_path); + } #endif handle->cb(handle, path, events, 0); From 160cd5629e4da7e86783873b0777d8a2ca414d39 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Mon, 8 Jan 2024 22:25:44 +0100 Subject: [PATCH 34/48] linux: retry fs op if unsupported by io_uring (#4268) Fallback to the threadpool if it returns `EOPNOTSUPP`. Fixes: https://github.com/nodejs/node/issues/50876 --- src/unix/fs.c | 10 ++++++++++ src/unix/internal.h | 1 + src/unix/linux.c | 6 ++++++ 3 files changed, 17 insertions(+) diff --git a/src/unix/fs.c b/src/unix/fs.c index 9671f0dd..3a74350f 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1630,6 +1630,16 @@ static void uv__fs_done(struct uv__work* w, int status) { } +void uv__fs_post(uv_loop_t* loop, uv_fs_t* req) { + uv__req_register(loop, req); + uv__work_submit(loop, + &req->work_req, + UV__WORK_FAST_IO, + uv__fs_work, + uv__fs_done); +} + + int uv_fs_access(uv_loop_t* loop, uv_fs_t* req, const char* path, diff --git a/src/unix/internal.h b/src/unix/internal.h index fe588513..bcb3be57 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -425,6 +425,7 @@ UV_UNUSED(static int uv__stat(const char* path, struct stat* s)) { } #if defined(__linux__) +void uv__fs_post(uv_loop_t* loop, uv_fs_t* req); ssize_t uv__fs_copy_file_range(int fd_in, off_t* off_in, diff --git a/src/unix/linux.c b/src/unix/linux.c index 7402a6fa..3c1313e7 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -1155,6 +1155,12 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) { uv__req_unregister(loop, req); iou->in_flight--; + /* If the op is not supported by the kernel retry using the thread pool */ + if (e->res == -EOPNOTSUPP) { + uv__fs_post(loop, req); + continue; + } + /* io_uring stores error codes as negative numbers, same as libuv. */ req->result = e->res; From a407b232f06aa2f6d1031bf2d126725a4e9e2a54 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Tue, 9 Jan 2024 10:10:35 +0000 Subject: [PATCH 35/48] freebsd: fix build on non-intel archs (#4276) KINFO_FILE_SIZE is only defined on Intel archs. Fixes: https://github.com/libuv/libuv/issues/4274 --- src/unix/kqueue.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index d7aa60e7..4d09edc0 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -493,7 +493,13 @@ static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) { if (handle->event_watcher.fd != -1 && (!uv__fstat(handle->event_watcher.fd, &statbuf) && !(statbuf.st_mode & S_IFDIR))) { - kf.kf_structsize = KINFO_FILE_SIZE; + /* we are purposely not using KINFO_FILE_SIZE here + * as it is not available on non intl archs + * and here it gives 1392 too on intel. + * anyway, the man page also mentions we can proceed + * this way. + */ + kf.kf_structsize = sizeof(kf); if (fcntl(handle->event_watcher.fd, F_KINFO, &kf) == 0) path = uv__basename_r(kf.kf_path); } From a7cbda92b69947f0a60df58d6d1520c84196476f Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Fri, 12 Jan 2024 18:54:51 +0800 Subject: [PATCH 36/48] unix: optimize uv__tcp_keepalive cpp directives (#4275) Reduce the amount of code being compiled and trim trailing whitespace in passing. --- src/unix/tcp.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index 31ecf5bd..799fca77 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -469,12 +469,13 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { if (delay == 0) return -1; - + +#ifdef __sun /* The implementation of TCP keep-alive on Solaris/SmartOS is a bit unusual * compared to other Unix-like systems. - * Thus, we need to specialize it on Solaris. */ -#ifdef __sun - /* There are two keep-alive mechanisms on Solaris: + * Thus, we need to specialize it on Solaris. + * + * There are two keep-alive mechanisms on Solaris: * - By default, the first keep-alive probe is sent out after a TCP connection is idle for two hours. * If the peer does not respond to the probe within eight minutes, the TCP connection is aborted. * You can alter the interval for sending out the first probe using the socket option TCP_KEEPALIVE_THRESHOLD @@ -485,7 +486,7 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { * The option value is an unsigned integer in milliseconds. The value zero indicates that TCP should never time out and * abort the connection when probing. The system default is controlled by the TCP ndd parameter tcp_keepalive_abort_interval. * The default is eight minutes. - * + * * - The second implementation is activated if socket option TCP_KEEPINTVL and/or TCP_KEEPCNT are set. * The time between each consequent probes is set by TCP_KEEPINTVL in seconds. * The minimum value is ten seconds. The maximum is ten days, while the default is two hours. @@ -499,43 +500,44 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { /* Kernel expects at most 10 days. */ if (idle > 10*24*60*60) idle = 10*24*60*60; - - /* `TCP_KEEPIDLE`, `TCP_KEEPINTVL`, and `TCP_KEEPCNT` were not available on Solaris + + /* `TCP_KEEPIDLE`, `TCP_KEEPINTVL`, and `TCP_KEEPCNT` were not available on Solaris * until version 11.4, but let's take a chance here. */ #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT) if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle))) return UV__ERR(errno); + intvl = idle/3; if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl))) return UV__ERR(errno); + cnt = 3; if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt))) return UV__ERR(errno); - return 0; -#endif - - /* Fall back to the first implementation of tcp-alive mechanism for older Solaris, +#else + /* Fall back to the first implementation of tcp-alive mechanism for older Solaris, * simulate the tcp-alive mechanism on other platforms via `TCP_KEEPALIVE_THRESHOLD` + `TCP_KEEPALIVE_ABORT_THRESHOLD`. */ idle *= 1000; /* kernel expects milliseconds */ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, &idle, sizeof(idle))) return UV__ERR(errno); - /* Note that the consequent probes will not be sent at equal intervals on Solaris, + /* Note that the consequent probes will not be sent at equal intervals on Solaris, * but will be sent using the exponential backoff algorithm. */ intvl = idle/3; cnt = 3; int time_to_abort = intvl * cnt; if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, &time_to_abort, sizeof(time_to_abort))) return UV__ERR(errno); - - return 0; #endif +#else /* !defined(__sun) */ + #ifdef TCP_KEEPIDLE if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) return UV__ERR(errno); #elif defined(TCP_KEEPALIVE) + /* Darwin/macOS uses TCP_KEEPALIVE in place of TCP_KEEPIDLE. */ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay))) return UV__ERR(errno); #endif @@ -552,6 +554,7 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { return UV__ERR(errno); #endif +#endif /* !defined(__sun) */ return 0; } From 3b6a1a14caeeeaf5510f2939a8e28ed9ba0ad968 Mon Sep 17 00:00:00 2001 From: Brad King Date: Sat, 13 Jan 2024 06:04:01 -0500 Subject: [PATCH 37/48] linux: disable io_uring on ppc64 and ppc64le (#4285) Since `io_uring` support was added, libuv's signal handler randomly segfaults on ppc64 when interrupting `epoll_pwait`. Disable it pending further investigation. Issue: https://github.com/libuv/libuv/issues/4283 --- src/unix/linux.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/unix/linux.c b/src/unix/linux.c index 3c1313e7..4164e90d 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -463,6 +463,9 @@ static int uv__use_io_uring(void) { #elif defined(__arm__) && __SIZEOF_POINTER__ == 4 /* See https://github.com/libuv/libuv/issues/4158. */ return 0; /* All 32 bits kernels appear buggy. */ +#elif defined(__powerpc64__) || defined(__ppc64__) + /* See https://github.com/libuv/libuv/issues/4283. */ + return 0; /* Random SIGSEGV in signal handler. */ #else /* Ternary: unknown=0, yes=1, no=-1 */ static _Atomic int use_io_uring; From f98516ddd5bf9dcffcc7a28b3b0d42d68a561ca1 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 19 Jan 2024 19:09:39 +0100 Subject: [PATCH 38/48] doc: add very basic Security Policy document (#4290) --- SECURITY.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..32abba81 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,27 @@ +# Security Policy + +## Supported Versions + +Currently, we are providing security updates for the latest release in the v1.x series: + +| Version | Supported | +| ------- | ------------------ | +| Latest v1.x | :white_check_mark: | + +## Reporting a Vulnerability + +If you believe you have found a security vulnerability in `libuv`, please use the [GitHub's private vulnerability reporting feature](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability) in the [libuv repository](https://github.com/libuv/libuv) to report it to us. + +This will allow us to assess the risk, and make a fix available before we add a bug report to the GitHub repository. + +Please do: + +* Provide as much information as you can about the vulnerability. +* Provide details about your configuration and environment, if applicable. + +Please do not: + +* Post any information about the vulnerability in public places. +* Attempt to exploit the vulnerability yourself. + +We take all security bugs seriously. Thank you for improving the security of `libuv`. We appreciate your efforts and responsible disclosure and will make every effort to acknowledge your contributions. \ No newline at end of file From 535efdf319ab719fbd3a7a4663339801d57b49c5 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sun, 21 Jan 2024 10:44:34 -0500 Subject: [PATCH 39/48] build: re-enable msvc-asan job on CI (#4289) --- .github/workflows/CI-win.yml | 22 ++++++++++++---------- CMakeLists.txt | 6 ++++++ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/.github/workflows/CI-win.yml b/.github/workflows/CI-win.yml index e66b107d..7dc3fdca 100644 --- a/.github/workflows/CI-win.yml +++ b/.github/workflows/CI-win.yml @@ -25,16 +25,12 @@ jobs: - {toolchain: Visual Studio 16 2019, arch: x64, server: 2019} - {toolchain: Visual Studio 17 2022, arch: Win32, server: 2022} - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022} - # Currently broken, see https://github.com/libuv/libuv/issues/4210 - #- {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: ASAN} + - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: ASAN} - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: UBSAN} - {toolchain: Visual Studio 17 2022, arch: arm64, server: 2022} steps: - uses: actions/checkout@v2 - - name: Envinfo - run: npx envinfo - name: Build - shell: cmd run: cmake -S . -B build -DBUILD_TESTING=ON -G "${{ matrix.config.toolchain }}" -A ${{ matrix.config.arch }} @@ -43,17 +39,23 @@ jobs: cmake --build build --config RelWithDebInfo + ${{ matrix.config.config == 'ASAN' && 'Copy-Item -Path "build\\*.exe" -Destination "build\\RelWithDebInfo\\"' || '' }} + + ${{ matrix.config.config == 'ASAN' && 'Copy-Item -Path "build\\*.dll" -Destination "build\\RelWithDebInfo\\"' || '' }} + ls -l build - - name: platform_output - if: ${{ matrix.config.arch != 'arm64' }} - shell: cmd - run: - build\\RelWithDebInfo\\uv_run_tests.exe platform_output + + ls -l build\\RelWithDebInfo - name: platform_output_a if: ${{ matrix.config.arch != 'arm64' }} shell: cmd run: build\\RelWithDebInfo\\uv_run_tests_a.exe platform_output + - name: platform_output + if: ${{ matrix.config.arch != 'arm64' }} + shell: cmd + run: + build\\RelWithDebInfo\\uv_run_tests.exe platform_output - name: Test # only valid with libuv-master with the fix for # https://github.com/libuv/leps/blob/master/005-windows-handles-not-fd.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a4d8069..3914f0d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -767,6 +767,12 @@ endif() if(MSVC) set(CMAKE_DEBUG_POSTFIX d) + get_filename_component(CMAKE_C_COMPILER_DIR ${CMAKE_C_COMPILER} DIRECTORY) + if(ASAN) + file(INSTALL "${CMAKE_C_COMPILER_DIR}/llvm-symbolizer.exe" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(INSTALL "${CMAKE_C_COMPILER_DIR}/clang_rt.asan_dynamic-x86_64.dll" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(INSTALL "${CMAKE_C_COMPILER_DIR}/clang_rt.asan_dbg_dynamic-x86_64.dll" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + endif() endif() message(STATUS "summary of build options: From 3f7191e5c27a0e1852fe046a5ec0512a47e4a409 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 5 Feb 2024 11:04:05 -0500 Subject: [PATCH 40/48] win/spawn: optionally run executable paths with no file extension (#4292) Add a process options flag to enable the optional behavior. Most users are likely recommended to set this flag by default, but it was deemed potentially breaking to set it by default in libuv. Co-authored-by: Kyle Edwards --- .github/workflows/CI-win.yml | 2 +- CMakeLists.txt | 12 +++++++ Makefile.am | 6 ++++ docs/src/process.rst | 12 ++++++- include/uv.h | 9 +++++- src/unix/process.c | 1 + src/win/process.c | 14 ++++++--- test/test-list.h | 4 +++ test/test-spawn.c | 61 ++++++++++++++++++++++++++++++++++++ 9 files changed, 113 insertions(+), 8 deletions(-) diff --git a/.github/workflows/CI-win.yml b/.github/workflows/CI-win.yml index 7dc3fdca..79a5abf4 100644 --- a/.github/workflows/CI-win.yml +++ b/.github/workflows/CI-win.yml @@ -93,7 +93,7 @@ jobs: cmake --install build --prefix "`pwd`/build/usr" mkdir -p build/usr/test build/usr/bin cp -av test/fixtures build/usr/test - cp -av build/uv_run_tests_a.exe build/uv_run_tests.exe \ + cp -av build/uv_run_tests_a.exe build/uv_run_tests.exe build/uv_run_tests_a_no_ext build/uv_run_tests_no_ext \ `${{ matrix.config.arch }}-w64-mingw32-gcc -print-file-name=libgcc_s_${{ matrix.config.libgcc }}-1.dll` \ `${{ matrix.config.arch }}-w64-mingw32-gcc -print-file-name=libwinpthread-1.dll` \ `${{ matrix.config.arch }}-w64-mingw32-gcc -print-file-name=libatomic-1.dll` \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 3914f0d6..5e8e0166 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -707,6 +707,12 @@ if(LIBUV_BUILD_TESTS) set_tests_properties(uv_test PROPERTIES ENVIRONMENT "LIBPATH=${CMAKE_BINARY_DIR}:$ENV{LIBPATH}") endif() + if(WIN32) + add_custom_command(TARGET uv_run_tests POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy + "$" + "$/uv_run_tests_no_ext") + endif() add_executable(uv_run_tests_a ${uv_test_sources} uv_win_longpath.manifest) target_compile_definitions(uv_run_tests_a PRIVATE ${uv_defines}) target_compile_options(uv_run_tests_a PRIVATE ${uv_cflags}) @@ -723,6 +729,12 @@ if(LIBUV_BUILD_TESTS) set_target_properties(uv_run_tests PROPERTIES LINKER_LANGUAGE CXX) set_target_properties(uv_run_tests_a PROPERTIES LINKER_LANGUAGE CXX) endif() + if(WIN32) + add_custom_command(TARGET uv_run_tests_a POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy + "$" + "$/uv_run_tests_a_no_ext") + endif() endif() # Now for some gibbering horrors from beyond the stars... diff --git a/Makefile.am b/Makefile.am index ff6f1b8a..a14228da 100644 --- a/Makefile.am +++ b/Makefile.am @@ -136,6 +136,12 @@ TESTS = test/run-tests check_PROGRAMS = test/run-tests test_run_tests_CFLAGS = $(AM_CFLAGS) +if WINNT +check-am: test/run-tests_no_ext +test/run-tests_no_ext: test/run-tests$(EXEEXT) + cp test/run-tests$(EXEEXT) test/run-tests_no_ext +endif + if SUNOS # Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers # on other platforms complain that the argument is unused during compilation. diff --git a/docs/src/process.rst b/docs/src/process.rst index 8acf7db3..8d2fdb3e 100644 --- a/docs/src/process.rst +++ b/docs/src/process.rst @@ -85,7 +85,14 @@ Data types * option is only meaningful on Windows systems. On Unix it is silently * ignored. */ - UV_PROCESS_WINDOWS_HIDE_GUI = (1 << 6) + UV_PROCESS_WINDOWS_HIDE_GUI = (1 << 6), + /* + * On Windows, if the path to the program to execute, specified in + * uv_process_options_t's file field, has a directory component, + * search for the exact file name before trying variants with + * extensions like '.exe' or '.cmd'. + */ + UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME = (1 << 7) }; .. c:type:: uv_stdio_container_t @@ -262,6 +269,9 @@ API .. versionchanged:: 1.24.0 Added `UV_PROCESS_WINDOWS_HIDE_CONSOLE` and `UV_PROCESS_WINDOWS_HIDE_GUI` flags. + .. versionchanged:: 1.48.0 Added the + `UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME` flag. + .. c:function:: int uv_process_kill(uv_process_t* handle, int signum) Sends the specified signal to the given process handle. Check the documentation diff --git a/include/uv.h b/include/uv.h index b1e58e6c..a62b3fa6 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1106,7 +1106,14 @@ enum uv_process_flags { * option is only meaningful on Windows systems. On Unix it is silently * ignored. */ - UV_PROCESS_WINDOWS_HIDE_GUI = (1 << 6) + UV_PROCESS_WINDOWS_HIDE_GUI = (1 << 6), + /* + * On Windows, if the path to the program to execute, specified in + * uv_process_options_t's file field, has a directory component, + * search for the exact file name before trying variants with + * extensions like '.exe' or '.cmd'. + */ + UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME = (1 << 7) }; /* diff --git a/src/unix/process.c b/src/unix/process.c index dd58c18d..4812a90f 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -972,6 +972,7 @@ int uv_spawn(uv_loop_t* loop, assert(!(options->flags & ~(UV_PROCESS_DETACHED | UV_PROCESS_SETGID | UV_PROCESS_SETUID | + UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME | UV_PROCESS_WINDOWS_HIDE | UV_PROCESS_WINDOWS_HIDE_CONSOLE | UV_PROCESS_WINDOWS_HIDE_GUI | diff --git a/src/win/process.c b/src/win/process.c index 50161b14..400722bd 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -304,8 +304,9 @@ static WCHAR* path_search_walk_ext(const WCHAR *dir, * - If there's really only a filename, check the current directory for file, * then search all path directories. * - * - If filename specified has *any* extension, search for the file with the - * specified extension first. + * - If filename specified has *any* extension, or already contains a path + * and the UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME flag is specified, + * search for the file with the exact specified filename first. * * - If the literal filename is not found in a directory, try *appending* * (not replacing) .com first and then .exe. @@ -331,7 +332,8 @@ static WCHAR* path_search_walk_ext(const WCHAR *dir, */ static WCHAR* search_path(const WCHAR *file, WCHAR *cwd, - const WCHAR *path) { + const WCHAR *path, + unsigned int flags) { int file_has_dir; WCHAR* result = NULL; WCHAR *file_name_start; @@ -372,7 +374,7 @@ static WCHAR* search_path(const WCHAR *file, file, file_name_start - file, file_name_start, file_len - (file_name_start - file), cwd, cwd_len, - name_has_ext); + name_has_ext || (flags & UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME)); } else { dir_end = path; @@ -935,6 +937,7 @@ int uv_spawn(uv_loop_t* loop, assert(!(options->flags & ~(UV_PROCESS_DETACHED | UV_PROCESS_SETGID | UV_PROCESS_SETUID | + UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME | UV_PROCESS_WINDOWS_HIDE | UV_PROCESS_WINDOWS_HIDE_CONSOLE | UV_PROCESS_WINDOWS_HIDE_GUI | @@ -1014,7 +1017,8 @@ int uv_spawn(uv_loop_t* loop, application_path = search_path(application, cwd, - path); + path, + options->flags); if (application_path == NULL) { /* Not found. */ err = ERROR_FILE_NOT_FOUND; diff --git a/test/test-list.h b/test/test-list.h index e97b941f..d30f02fa 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -507,6 +507,8 @@ TEST_DECLARE (listen_no_simultaneous_accepts) TEST_DECLARE (fs_stat_root) TEST_DECLARE (spawn_with_an_odd_path) TEST_DECLARE (spawn_no_path) +TEST_DECLARE (spawn_no_ext) +TEST_DECLARE (spawn_path_no_ext) TEST_DECLARE (ipc_listen_after_bind_twice) TEST_DECLARE (win32_signum_number) #else @@ -1027,6 +1029,8 @@ TASK_LIST_START TEST_ENTRY (fs_stat_root) TEST_ENTRY (spawn_with_an_odd_path) TEST_ENTRY (spawn_no_path) + TEST_ENTRY (spawn_no_ext) + TEST_ENTRY (spawn_path_no_ext) TEST_ENTRY (ipc_listen_after_bind_twice) TEST_ENTRY (win32_signum_number) #else diff --git a/test/test-spawn.c b/test/test-spawn.c index 33552717..6a848747 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1397,6 +1397,67 @@ TEST_IMPL(spawn_no_path) { MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } + + +TEST_IMPL(spawn_no_ext) { + char new_exepath[1024]; + + init_process_options("spawn_helper1", exit_cb); + options.flags |= UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME; + snprintf(new_exepath, sizeof(new_exepath), "%.*s_no_ext", + (int) (exepath_size - sizeof(".exe") + 1), + exepath); + options.file = options.args[0] = new_exepath; + + ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(1, close_cb_called); + + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +} + + +TEST_IMPL(spawn_path_no_ext) { + int r; + int len; + int file_len; + char file[64]; + char path[1024]; + char* env[2]; + + /* Set up the process, but make sure that the file to run is relative and + * requires a lookup into PATH. */ + init_process_options("spawn_helper1", exit_cb); + options.flags |= UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME; + + /* Set up the PATH env variable */ + for (len = strlen(exepath), file_len = 0; + exepath[len - 1] != '/' && exepath[len - 1] != '\\'; + len--, file_len++); + snprintf(file, sizeof(file), "%.*s_no_ext", + (int) (file_len - sizeof(".exe") + 1), + exepath + len); + exepath[len] = 0; + snprintf(path, sizeof(path), "PATH=%s", exepath); + + env[0] = path; + env[1] = NULL; + + options.file = options.args[0] = file; + options.env = env; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == UV_ENOENT || r == UV_EACCES); + ASSERT_OK(uv_is_active((uv_handle_t*) &process)); + uv_close((uv_handle_t*) &process, NULL); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +} #endif #ifndef _WIN32 From 129362f35648a61ab19ab665014d2013731a986b Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 5 Feb 2024 15:24:07 -0500 Subject: [PATCH 41/48] win: fix ESRCH implementation (#4301) Per documentation, this was the wrong way to test for ESRCH. This hopefully fixes it. Fixes: https://github.com/libuv/libuv/issues/4300 --- src/win/process.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/win/process.c b/src/win/process.c index 400722bd..4e94dee9 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -1307,7 +1307,6 @@ static int uv__kill(HANDLE process_handle, int signum) { case SIGINT: { /* Unconditionally terminate the process. On Windows, killed processes * normally return 1. */ - DWORD status; int err; if (TerminateProcess(process_handle, 1)) @@ -1317,8 +1316,7 @@ static int uv__kill(HANDLE process_handle, int signum) { * TerminateProcess will fail with ERROR_ACCESS_DENIED. */ err = GetLastError(); if (err == ERROR_ACCESS_DENIED && - GetExitCodeProcess(process_handle, &status) && - status != STILL_ACTIVE) { + WaitForSingleObject(process_handle, 0) == WAIT_OBJECT_0) { return UV_ESRCH; } @@ -1327,15 +1325,16 @@ static int uv__kill(HANDLE process_handle, int signum) { case 0: { /* Health check: is the process still alive? */ - DWORD status; - - if (!GetExitCodeProcess(process_handle, &status)) - return uv_translate_sys_error(GetLastError()); - - if (status != STILL_ACTIVE) - return UV_ESRCH; - - return 0; + switch (WaitForSingleObject(process_handle, 0)) { + case WAIT_OBJECT_0: + return UV_ESRCH; + case WAIT_FAILED: + return uv_translate_sys_error(GetLastError()); + case WAIT_TIMEOUT: + return 0; + default: + return UV_UNKNOWN; + } } default: @@ -1370,7 +1369,7 @@ int uv_kill(int pid, int signum) { if (pid == 0) { process_handle = GetCurrentProcess(); } else { - process_handle = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, + process_handle = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, pid); } From 10f313631c10ee508e17b35bdebf5adf0fff90fd Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 6 Feb 2024 07:52:21 +0100 Subject: [PATCH 42/48] Revert "unix: restore signal disposition to previous one (#4216)" (#4302) This reverts commit b9421d70665352138557d2d2338656a38ac70691. Refs: https://github.com/libuv/libuv/issues/4299 Refs: https://github.com/libuv/libuv/issues/4248 --- src/unix/signal.c | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/src/unix/signal.c b/src/unix/signal.c index 2b556708..bc4206e6 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -32,18 +32,11 @@ # define SA_RESTART 0 #endif -#define UV__NSIG 128 - typedef struct { uv_signal_t* handle; int signum; } uv__signal_msg_t; -typedef struct { - struct sigaction acts[UV__NSIG]; - char acts_presented_flags[UV__NSIG]; -} uv__sigactions_t; - RB_HEAD(uv__signal_tree_s, uv_signal_s); @@ -57,23 +50,11 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2); static void uv__signal_stop(uv_signal_t* handle); static void uv__signal_unregister_handler(int signum); -static void uv__sigaction_set(int signum, struct sigaction *sa); -static int uv__sigaction_isset(int signum); static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT; static struct uv__signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree); static int uv__signal_lock_pipefd[2] = { -1, -1 }; -static uv__sigactions_t uv__sigactions; - -static void uv__sigaction_set(int signum, struct sigaction *sa) { - uv__sigactions.acts[signum] = *sa; - uv__sigactions.acts_presented_flags[signum] = 1; -} - -static int uv__sigaction_isset(int signum) { - return uv__sigactions.acts_presented_flags[signum] == 0 ? 0 : 1; -} RB_GENERATE_STATIC(uv__signal_tree_s, uv_signal_s, tree_entry, @@ -243,7 +224,6 @@ static void uv__signal_handler(int signum) { static int uv__signal_register_handler(int signum, int oneshot) { /* When this function is called, the signal lock must be held. */ struct sigaction sa; - struct sigaction sa_old; /* XXX use a separate signal stack? */ memset(&sa, 0, sizeof(sa)); @@ -254,11 +234,10 @@ static int uv__signal_register_handler(int signum, int oneshot) { if (oneshot) sa.sa_flags |= SA_RESETHAND; - if (sigaction(signum, &sa, &sa_old)) + /* XXX save old action so we can restore it later on? */ + if (sigaction(signum, &sa, NULL)) return UV__ERR(errno); - uv__sigaction_set(signum, &sa_old); - return 0; } @@ -266,10 +245,9 @@ static int uv__signal_register_handler(int signum, int oneshot) { static void uv__signal_unregister_handler(int signum) { /* When this function is called, the signal lock must be held. */ struct sigaction sa; - - assert(uv__sigaction_isset(signum)); - - sa = uv__sigactions.acts[signum]; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; /* sigaction can only fail with EINVAL or EFAULT; an attempt to deregister a * signal implies that it was successfully registered earlier, so EINVAL From bb6fbcf6e75201cebac30220366d4aff620b8765 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 7 Feb 2024 10:43:29 +0100 Subject: [PATCH 43/48] unix,win: reset the timer queue on stop (#4304) As there were instances where this didn't happen and could cause memory corruption issues. Refs: https://github.com/libuv/libuv/issues/4248 --- src/timer.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/timer.c b/src/timer.c index b57d6427..4525199d 100644 --- a/src/timer.c +++ b/src/timer.c @@ -94,20 +94,18 @@ int uv_timer_start(uv_timer_t* handle, return 0; } -static void timer_stop(uv_timer_t* handle) { - heap_remove(timer_heap(handle->loop), - (struct heap_node*) &handle->node.heap, - timer_less_than); - uv__handle_stop(handle); - uv__queue_init(&handle->node.queue); -} - int uv_timer_stop(uv_timer_t* handle) { - if (uv__is_active(handle)) - timer_stop(handle); - else + if (uv__is_active(handle)) { + heap_remove(timer_heap(handle->loop), + (struct heap_node*) &handle->node.heap, + timer_less_than); + uv__handle_stop(handle); + } else { uv__queue_remove(&handle->node.queue); + } + + uv__queue_init(&handle->node.queue); return 0; } @@ -181,7 +179,7 @@ void uv__run_timers(uv_loop_t* loop) { if (handle->timeout > loop->time) break; - timer_stop(handle); + uv_timer_stop(handle); uv__queue_insert_tail(&ready_queue, &handle->node.queue); } From 0f2d7e784a256b54b2385043438848047bc2a629 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 18 Jan 2024 14:51:40 +0100 Subject: [PATCH 44/48] fix: always zero-terminate idna output Fixes: https://github.com/libuv/libuv/security/advisories/GHSA-f74f-cvh7-c6q6 --- src/idna.c | 5 +++-- test/test-idna.c | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/idna.c b/src/idna.c index 3cf79ca9..4638546d 100644 --- a/src/idna.c +++ b/src/idna.c @@ -356,9 +356,10 @@ ssize_t uv__idna_toascii(const char* s, const char* se, char* d, char* de) { return rc; } - if (d < de) - *d++ = '\0'; + if (d >= de) + return UV_EINVAL; + *d++ = '\0'; return d - ds; /* Number of bytes written. */ } diff --git a/test/test-idna.c b/test/test-idna.c index bcacfc8a..5f8d696a 100644 --- a/test/test-idna.c +++ b/test/test-idna.c @@ -100,6 +100,7 @@ TEST_IMPL(utf8_decode1) { TEST_IMPL(utf8_decode1_overrun) { const char* p; char b[1]; + char c[1]; /* Single byte. */ p = b; @@ -113,6 +114,9 @@ TEST_IMPL(utf8_decode1_overrun) { ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + 1)); ASSERT_PTR_EQ(p, b + 1); + b[0] = 0x7F; + ASSERT_EQ(UV_EINVAL, uv__idna_toascii(b, b + 1, c, c + 1)); + return 0; } From 3530bcc30350d4a6ccf35d2f7b33e23292b9de70 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 18 Jan 2024 14:52:38 +0100 Subject: [PATCH 45/48] fix: reject zero-length idna inputs Fixes: https://github.com/libuv/libuv/security/advisories/GHSA-f74f-cvh7-c6q6 --- src/idna.c | 3 +++ test/test-idna.c | 1 + 2 files changed, 4 insertions(+) diff --git a/src/idna.c b/src/idna.c index 4638546d..efc5f283 100644 --- a/src/idna.c +++ b/src/idna.c @@ -322,6 +322,9 @@ ssize_t uv__idna_toascii(const char* s, const char* se, char* d, char* de) { char* ds; int rc; + if (s == se) + return UV_EINVAL; + ds = d; si = s; diff --git a/test/test-idna.c b/test/test-idna.c index 5f8d696a..3c4820f7 100644 --- a/test/test-idna.c +++ b/test/test-idna.c @@ -115,6 +115,7 @@ TEST_IMPL(utf8_decode1_overrun) { ASSERT_PTR_EQ(p, b + 1); b[0] = 0x7F; + ASSERT_EQ(UV_EINVAL, uv__idna_toascii(b, b + 0, c, c + 1)); ASSERT_EQ(UV_EINVAL, uv__idna_toascii(b, b + 1, c, c + 1)); return 0; From e0327e1d508b8207c9150b6e582f0adf26213c39 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 7 Feb 2024 20:27:58 +0100 Subject: [PATCH 46/48] test: empty strings are not valid IDNA Fixes: https://github.com/libuv/libuv/security/advisories/GHSA-f74f-cvh7-c6q6 --- test/test-idna.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-idna.c b/test/test-idna.c index 3c4820f7..28f9eaaa 100644 --- a/test/test-idna.c +++ b/test/test-idna.c @@ -151,8 +151,8 @@ TEST_IMPL(idna_toascii) { /* Illegal inputs. */ F("\xC0\x80\xC1\x80", UV_EINVAL); /* Overlong UTF-8 sequence. */ F("\xC0\x80\xC1\x80.com", UV_EINVAL); /* Overlong UTF-8 sequence. */ + F("", UV_EINVAL); /* No conversion. */ - T("", ""); T(".", "."); T(".com", ".com"); T("example", "example"); From e9f29cb984231524e3931aa0ae2c5dae1a32884e Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 7 Feb 2024 20:20:07 +0000 Subject: [PATCH 48/48] 2024.02.07, Version 1.48.0 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.47.0: * misc: remove deprecated stalebot file (Jameson Nash) * build: disable windows asan buildbot (Ben Noordhuis) * test: don't run tcp_writealot under msan (Ben Noordhuis) * build,win: remove extraneous -lshell32 (Ben Noordhuis) * unix: ignore ifaddrs with NULL ifa_addr (Stephen Gallagher) * unix,win: utility for setting priority for thread (Hao Hu) * pipe: add back error handling to connect / bind (Jameson Nash) * test: check if ipv6 link-local traffic is routable (Ben Noordhuis) * win: remove check for UV_PIPE_NO_TRUNCATE (Jameson Nash) * linux: disable io_uring on hppa below kernel 6.1.51 (matoro) * unix,win: fix read past end of pipe name buffer (Ben Noordhuis) * unix: unbreak macOS < 10.14 (Sergey Fedorov) * aix: disable ipv6 link local (Abdirahim Musse) * doc: move cjihrig to emeriti (cjihrig) * unix: correct pwritev conditional (Bo Anderson) * test_fs.c: Fix issue on 32-bit systems using btrfs (Stephen Gallagher) * misc: ignore libuv-release-tool files (Jameson Nash) * win: honor NoDefaultCurrentDirectoryInExePath env var (Ardi Nugraha) * idna: fix compilation warning (Saúl Ibarra Corretgé) * linux: remove HAVE_IFADDRS_H macro (Ben Noordhuis) * test: skip tcp-write-in-a-row on IBM i (Abdirahim Musse) * build,win: work around missing uuid.dll on MinGW (Anton Bachin) * win: stop using deprecated names (Matheus Izvekov) * unix,win: fix busy loop with zero timeout timers (Matheus Izvekov) * aix,ibmi: use uv_interface_addresses instead of getifaddrs (Abdirahim Musse) * linux: fix bind/connect for abstract sockets (Santiago Gimeno) * win: replace c99 comments with c89 comments (Trevor Flynn) * build: add .cache clangd folder to .gitignore (Juan José Arboleda) * unix: support full TCP keep-alive on Solaris (Andy Pan) * freebsd: fix F_KINFO file path handling (David Carlier) * linux: retry fs op if unsupported by io_uring (Santiago Gimeno) * freebsd: fix build on non-intel archs (David Carlier) * unix: optimize uv__tcp_keepalive cpp directives (Andy Pan) * linux: disable io_uring on ppc64 and ppc64le (Brad King) * doc: add very basic Security Policy document (Santiago Gimeno) * build: re-enable msvc-asan job on CI (Jameson Nash) * win/spawn: optionally run executable paths with no file extension (Brad King) * win: fix ESRCH implementation (Jameson Nash) * unix,win: reset the timer queue on stop (Santiago Gimeno) * fix: always zero-terminate idna output (Ben Noordhuis) * fix: reject zero-length idna inputs (Ben Noordhuis) * test: empty strings are not valid IDNA (Santiago Gimeno) * Merge pull request from GHSA-f74f-cvh7-c6q6 (Ben Noordhuis) --- AUTHORS | 7 ++++ ChangeLog | 91 ++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 2 +- include/uv/version.h | 8 ++-- 4 files changed, 103 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index 6bf1a9fa..f3942ced 100644 --- a/AUTHORS +++ b/AUTHORS @@ -560,3 +560,10 @@ prubel Per Allansson <65364157+per-allansson@users.noreply.github.com> Matheus Izvekov Christian Heimlich +Hao Hu <33607772+hhu8@users.noreply.github.com> +matoro <12038583+matoro@users.noreply.github.com> +Bo Anderson +Ardi Nugraha <33378542+ardi-nugraha@users.noreply.github.com> +Anton Bachin +Trevor Flynn +Andy Pan diff --git a/ChangeLog b/ChangeLog index 0a3905b2..05c1cb7e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,94 @@ +2024.02.07, Version 1.48.0 (Stable) + +Changes since version 1.47.0: + +* misc: remove deprecated stalebot file (Jameson Nash) + +* build: disable windows asan buildbot (Ben Noordhuis) + +* test: don't run tcp_writealot under msan (Ben Noordhuis) + +* build,win: remove extraneous -lshell32 (Ben Noordhuis) + +* unix: ignore ifaddrs with NULL ifa_addr (Stephen Gallagher) + +* unix,win: utility for setting priority for thread (Hao Hu) + +* pipe: add back error handling to connect / bind (Jameson Nash) + +* test: check if ipv6 link-local traffic is routable (Ben Noordhuis) + +* win: remove check for UV_PIPE_NO_TRUNCATE (Jameson Nash) + +* linux: disable io_uring on hppa below kernel 6.1.51 (matoro) + +* unix,win: fix read past end of pipe name buffer (Ben Noordhuis) + +* unix: unbreak macOS < 10.14 (Sergey Fedorov) + +* aix: disable ipv6 link local (Abdirahim Musse) + +* doc: move cjihrig to emeriti (cjihrig) + +* unix: correct pwritev conditional (Bo Anderson) + +* test_fs.c: Fix issue on 32-bit systems using btrfs (Stephen Gallagher) + +* misc: ignore libuv-release-tool files (Jameson Nash) + +* win: honor NoDefaultCurrentDirectoryInExePath env var (Ardi Nugraha) + +* idna: fix compilation warning (Saúl Ibarra Corretgé) + +* linux: remove HAVE_IFADDRS_H macro (Ben Noordhuis) + +* test: skip tcp-write-in-a-row on IBM i (Abdirahim Musse) + +* build,win: work around missing uuid.dll on MinGW (Anton Bachin) + +* win: stop using deprecated names (Matheus Izvekov) + +* unix,win: fix busy loop with zero timeout timers (Matheus Izvekov) + +* aix,ibmi: use uv_interface_addresses instead of getifaddrs (Abdirahim Musse) + +* linux: fix bind/connect for abstract sockets (Santiago Gimeno) + +* win: replace c99 comments with c89 comments (Trevor Flynn) + +* build: add .cache clangd folder to .gitignore (Juan José Arboleda) + +* unix: support full TCP keep-alive on Solaris (Andy Pan) + +* freebsd: fix F_KINFO file path handling (David Carlier) + +* linux: retry fs op if unsupported by io_uring (Santiago Gimeno) + +* freebsd: fix build on non-intel archs (David Carlier) + +* unix: optimize uv__tcp_keepalive cpp directives (Andy Pan) + +* linux: disable io_uring on ppc64 and ppc64le (Brad King) + +* doc: add very basic Security Policy document (Santiago Gimeno) + +* build: re-enable msvc-asan job on CI (Jameson Nash) + +* win/spawn: optionally run executable paths with no file extension (Brad King) + +* win: fix ESRCH implementation (Jameson Nash) + +* unix,win: reset the timer queue on stop (Santiago Gimeno) + +* fix: always zero-terminate idna output (Ben Noordhuis) + +* fix: reject zero-length idna inputs (Ben Noordhuis) + +* test: empty strings are not valid IDNA (Santiago Gimeno) + +* Merge pull request from GHSA-f74f-cvh7-c6q6 (Ben Noordhuis) + + 2023.11.06, Version 1.47.0 (Stable), be6b81a352d17513c95be153afcb3148f1a451cd Changes since version 1.46.0: diff --git a/configure.ac b/configure.ac index f9b5aa53..d4cc003e 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.47.1-dev], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.48.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index 8a5e3c09..d6a61a10 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 47 -#define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 48 +#define UV_VERSION_PATCH 0 +#define UV_VERSION_IS_RELEASE 1 +#define UV_VERSION_SUFFIX "" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \