Use GetProcessAffinityMask() to estimate the available parallelism.
Before this commit, it simply used the number of available CPUs.
Fixes: https://github.com/libuv/libuv/issues/4520
In #4470, I accidentally copied the bug from unix, where calling
uv_stream_set_blocking can cause the whole process to hang on a read.
However, unlike unix, where libuv attempts to set the O_NONBLOCK flag in
uv_pipe_open (as long as the handle never gets passed to uv_spawn), the
NT kernel is not capable of enabling OVERLAPPED operation later (but
fortunately, it also cannot disable it later too).
This implementation might be good to copy to unix (using FIONREAD) to
address the same bug that happens there if the user has called uv_spawn
or uv_stream_set_non_blocking on this handle in the past.
Refactor / cleanup arithmetic for unix -> win filetime conversion
in order to avoid multiplication overflow.
Fixes:
```
src/win/fs.c:106:48: runtime error: signed integer overflow: 1702781567 * 10 cannot be represented in type 'long'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/win/fs.c:106:48 in
```
Co-authored-by: Jameson Nash <vtjnash@gmail.com>
MSVC does not actually support ubsan. There is a long-standing ticket
requesting this:
https://developercommunity.visualstudio.com/t/add-support-for-ubsan/840750
There are no known compilers that currently accept the
`/fsanitize=undefined` spelling. clang-cl accepts `-fsanitize...`,
same as regular clang.
Also passes no-sanitizer-recover so that tests actually fail.
Fix various ubsan-detected errors, including:
* win: fix req-inl.h ubsan failure
Don't use CONTAINING_RECORD macro from WinSDK, as it doesn't use the
right trick which avoids member access on null pointer.
Fixes:
```
src/win/req-inl.h:86:10: runtime error: member access within null pointer of type 'uv_req_t' (aka 'struct uv_req_s')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior D:/a/libuv/libuv/src/win/req-inl.h:86:10
```
* test: fix ubsan failure on udp_ref3
Don't call functions through different function type.
Fixes:
```
src/win/udp.c:537:5: runtime error: call to function req_cb through pointer to incorrect function type 'void (*)(struct uv_udp_send_s *, int)'
test\test-ref.c:66: note: req_cb defined here
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/win/udp.c:537:5 in
```
* win: fix process-stdio.c ubsan failure
When accessing HANDLEs within the stdio buffer, use memcpy / memset in order to respect alignment.
Fixes:
```
src/win/process-stdio.c:197:5: runtime error: store to misaligned address 0x0230ee72d107 for type 'HANDLE' (aka 'void *'), which requires 8 byte alignment
0x0230ee72d107: note: pointer points here
00 00 cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd fd fd fd fd
^
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/win/process-stdio.c:197:5 in
```
* win: fix getaddrinfo.c ubsan failure
Reworks buffer alignment handling to respect requirements.
Fixes:
```
src/win/getaddrinfo.c:157:23: runtime error: member access within misaligned address 0x0290e4c6a17c for type 'struct addrinfo', which requires 8 byte alignment
0x0290e4c6a17c: note: pointer points here
00 00 00 00 cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd
^
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/win/getaddrinfo.c:157:23 in
```
* win: fix pipe.c ubsan failure
Changes "random" representation from pointer to number.
Fixes:
```
src/win/pipe.c:234:11: runtime error: applying non-zero offset to non-null pointer 0xffffffffffffffff produced null pointer
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/win/pipe.c:234:11 in
```
* unix: fix stream.c ubsan failure
Avoids performing pointer arithmetic on null pointer.
Fixes:
```
src/unix/stream.c:701:15: runtime error: applying zero offset to null pointer
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /Users/runner/work/libuv/libuv/src/unix/stream.c:701:15 in
```
This fixes a race condition if multiple threads are reading from the
same NamedPipe, which could previously lead to a deadlock situation. We
also substantially improve performance now also, since the PeekFile
call is unnecessary overhead with this change. This API was added in
Windows Vista.
Related to #4467, though doesn't address any of the problems there. I
believe that someone could now implement uv__pipe_try_write using
this same code pattern however.
Windows added a new API for file information, which doesn't have to
open the file thus greatly improving performance:
https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyname
The stat functions are already covered by tests, so no test was added
here. I considered comparing the result of old and new code, but that
would require exposing internal fs functions, and we would be testing
Windows functionality, not libuv.
If the corresponding environment variables are empty, the
uv_us_homedir() and uv_os_tmpdir() return garbage values. The reason
for this situation is the Windows API which doesn't return an error
even if the path is empty.
This PR fixes this problem by checking the return value of the API
call. If it is not an error and the length of the value is less than 3,
uv_us_homedir() and uv_os_tmpdir() will return UV_ENOENT.
Fixes: https://github.com/libuv/libuv/issues/2328
This was incorrectly mapped originally, which makes for confusing error
messages about an EPIPE if a program happens to (unwisely) set PIPE_WAIT
on the handle. It is unclear to me if libuv should try to handle this in
some meaningful way, and very unclear what that way would look like, but
at least expose this to the caller with the correct errno translation.
CreateProcessW() in uv_spawn() on Windows will fail with
ERROR_BAD_EXE_FORMAT if attempting to run a file that is not
an executable.
Refs: https://github.com/libuv/libuv/issues/2348
Make it less likely for the thread-local error value to get
clobbered between performing the operation and checking the result.
Refs: https://github.com/libuv/libuv/issues/4338
It might happen that only using `WaitForSingleObject()` with timeout 0
could return WAIT_TIMEOUT as the process might not have been signaled
yet. To improve things, first use `GetExitCodeProcess()` and check
that `status` is not `STILL_ACTIVE`. Then, to cover for the case that the exit
code was actually `STILL_ACTIVE` use `WaitForSingleObject()`. This could
still be prone to the race condition but only for that case.
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 <kyle.edwards@kitware.com>
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().
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
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.
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
uv_os_uname() on Windows queries the registry value "HKEY_LOCAL_MACHINE\
SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName" to fill
uv_utsname_t. If calling application was compiled for x86 and run on a
x86_64 host, that query is redirected to "Computer\HKEY_LOCAL_MACHINE\
SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\ProductName"
instead.
For whatever reason, the value of 'ProductName' in the 32-bit registry
section on 64-bit Windows sometimes differs from the 64-bit equivalent
value and is inaccurate (e.g. containing the data
"Windows 10 Enterprise" while the 64-bit value accurately contains
"Windows 10 Pro").
Adds the 'KEY_WOW64_64KEY' security descriptor when opening the
appropriate registry key so that the value of ProductName is always
taken from the primary registry on 64-bit systems, regardless of
compiled architecture. The descriptor is safely ignored on 32-bit hosts.
As promised in #2970, this attempts to migrate code to a common set of
utilities in a common place in the code and use them everywhere. This
also exports the functionality, since the Windows API with
WideCharToMultiByte is fairly verbose relative to what libuv and
libuv's clients typically need, so it is useful not to require clients
to reimplement this conversion logic unnecessarily (and because Windows
is not 64-bit ready here, but this implementation is.)
Make sure this handle is functional. The Windows kernel seems to have a
bug that if the first use of AssignProcessToJobObject is for a Windows
Store program, subsequent attempts to use the handle with fail with
INVALID_PARAMETER (87). This is possilby because all uses of the handle
must be for the same Terminal Services session. We can ensure it is
tied to our current session now by adding ourself to it. We could
remove ourself afterwards, but there doesn't seem to be a reason to.
Secondly, we start the process suspended so that we can make sure we
added it to the job control object before it does anything itself (such
as launch more jobs or exit).
Fixes: https://github.com/JuliaLang/julia/issues/51461
Adjust include order to avoid redefining `CTL_CODE`, `FILE_READ_ACCESS`,
and `FILE_WRITE_ACCESS`. Without this, compilation shows:
```
...\um\winioctl.h(273): warning C4005: 'CTL_CODE': macro redefinition
...\src\win\winapi.h(4497): note: see previous definition of 'CTL_CODE'
...\um\winioctl.h(320): warning C4005: 'FILE_READ_ACCESS': macro redefinition
...\src\win\winapi.h(4488): note: see previous definition of 'FILE_READ_ACCESS'
...\um\winioctl.h(321): warning C4005: 'FILE_WRITE_ACCESS': macro redefinition
...\src\win\winapi.h(4492): note: see previous definition of 'FILE_WRITE_ACCESS'
```
The initial run of timers shouldn't happen if uv_stop() has been run
before uv_run() was called, and for backwards compatibility they also
shouldn't run if they have been unref'd before calling uv_run().
Recent versions of gcc have started emitting warnings about the liberal
type casting inside the QUEUE macros. Although the warnings are false
positives, let's use them as the impetus to switch to a type-safer and
arguably cleaner approach.
Fixes: https://github.com/libuv/libuv/issues/4019
This commit adds the ability to dump core when sending the `SIGQUIT`
signal on Windows. The change reads in the current registry setting for
local dumps, and attempts to write out to that location before killing
the process. See [collecting-user-mode-dumps] for registry and pathing
details. This behavior mimics that of the dumps created by the typical
Windows Error Reporting mechanism.
[collecting-user-mode-dumps]: https://learn.microsoft.com/en-us/windows/win32/wer/collecting-user-mode-dumps
The worker pool calls all callbacks locally within the queue. So the
value of nevents doesn't properly reflect that case. Increase the number
of events directly from the worker pool's callback to correct this.
In order to properly determine if the events_waiting counter needs to be
incremented, store the timeout value at the time the event provider was
called.
The maximum number of times timers should run when uv_run() is called
with UV_RUN_ONCE and UV_RUN_NOWAIT is 1. Do that by conditionally
calling timers before entering the while loop when called with
UV_RUN_DEFAULT.
The reason to always run timers at the end of the while loop, instead of
at the beginning, is to help enforce the conceptual event loop model.
Which starts when entering the event provider (e.g. calling poll).
Other than only allowing timers to be processed once per uv_run()
execution, the only other noticeable change this will show is if all the
following are true:
* uv_run() is called with UV_RUN_NOWAIT or UV_RUN_ONCE.
* An event is waiting to be received when poll is called.
* Execution time between the call to uv_timer_start() and entering the
while loop is longer than the timeout.
If all these are true, then timers that would have executed before
entering the event provider will now be executed afterward.
Fixes: https://github.com/libuv/libuv/issues/3686
Co-authored-by: Momtchil Momtchev <momtchil@momtchev.com>
This code would previously get confused between rounds of the barrier
being called and a thread might incorrectly get stuck (deadlock) if the
next round started before that thread had exited the current round.
Avoid that by not starting the next round in++ before out-- has reached
zero indicating that all threads have left the prior round.
And fix it that on Windows by replacing the implementation with the one
from unix. There are some awkward platform-specific redirection here
with an extra malloc that is not needed on Win32, but that will be fixed
in libuv v2.
Fixes: https://github.com/libuv/libuv/issue/3872
The call to uv__cwd() always returns a new allocation. The previously
allocated utf16_buffer needs to be free'd before passing it in to
receive the next allocation.
File system operations may return uid and gid values, which we may want
to pretty-print. We already have the code for getting information for
the current user, so just need to add a parameter to make it exposed for
every user. We expose information about groups in a similar manner also.
In Node.js, fs.readlink() on a non-symlink file used to throw an UNKNOWN
error on Windows. This change maps ERROR_NOT_A_REPARSE_POINT to
UV_EINVAL, so that now it throws EINVAL just like other platforms.
This is handled explicitly in `fs__readlink`, since elsewhere it might
map to EPERM instead (such as in `link`).
Return `UV_EAGAIN` on `ERROR_OPERATION_ABORTED`.
Use the correct format for `overlapped.hEvent`.
Some refactoring to always wait for the overlapped result.
Modernize tests and some improvements.
Calling uv_fs_fstat for file types other then disk type was resulting in
error on Windows while it was retrieving data on Linux. This change
enables getting fstat for pipes and character files on Windows with data
fetched being as reasonable as possible.
A simple test is also added to check this behavior on all platforms. It
uses stdin, stdout and stderr. uv_fs_fstat needs to pass with disk files
pipes and character files (eg. console).
Refs: https://github.com/nodejs/node/issues/40006
Co-authored-by: Jameson Nash <vtjnash@gmail.com>
The following metrics are now always recorded and available via the new
uv_metrics_info() API.
* loop_count: Number of event loop iterations.
* events: Total number of events processed by the event handler.
* events_waiting: Total number of events waiting in the event queue when
the event provider request was made.
Benchmarking has shown no noticeable impact recording these metrics.
PR-URL: https://github.com/libuv/libuv/pull/3749
Make unices and windows consistent when closing a pipe while it's
connecting so they all return `UV_ECANCELED`.
Avoid race condition between `pipe_connect_thread_proc()` and `uv_close()` when
accessing `handle->name`.
Fixes: https://github.com/libuv/libuv/issues/3578
Backported thread affinity feature and related dependency commits
from master. It will add support for those APIs: uv_cpumask_size,
uv_thread_setaffinity, uv_thread_getaffinity.
The supported platforms are Linux, Freebsd, and Windows.
Empty implementations (returning UV_ENOTSUP) on non-supported platforms
(such as OS X and AIX).
In the old version of uv_pipe_open, the parent process ID is used
always. If the open pipe is used in the same process, the parent
process will be obtained incorrectly.
Now we first get the client pid and compare it with its own pid. If it
is the same, then get the server pid. If the two are the same, then the
pipe is from the same process.
Fixes: https://github.com/libuv/libuv/issues/3766
Another thread can change the working directory between calls to
GetCurrentDirectoryW().
The first call was used to determine the size of the buffer to use in
the second call. Retry if the reported size does not match the expected
size because the buffer's contents is undefined in that case.
uv_exepath() wrote the nul byte *after* the end of the buffer. It's not
necessary to write said nul byte in the first place because that was a
workaround for a bug in the Windows XP version of GetModuleFileName().
Fix uv_cwd() in the same fashion, it doesn't need the nul byte either.
Fixes: https://github.com/libuv/libuv/issues/3691
Split this off from endgame, so that it can be handled separately and
earlier, rather than trying to detect inside endgame which case we are
in. There appear to be some race conditions on the `handle` field still
however, which this does not yet attempt to address.
Previously, Windows would always defer event processing to the loop
after they were received. This could cause confusion for users who were
using prepare and idle callbacks, as seen from this bug in nodejs[^1] and
this discussion in libuv[^2], and even some discrepancies in the libuv
tests too[^3].
[^1]: https://github.com/nodejs/node/pull/42340
[^2]: https://github.com/libuv/libuv/discussions/3550
[^3]: See change to test-spawn.c in this PR
So rather than declare those usages to be wrong, we change libuv to meet
those users expectations.
Replaces: https://github.com/libuv/libuv/pull/3585
If `uv_close` was called while a connect was pending, we would fail to
release the resources for the connection, since we had not yet set the
type of the struct.
Fix a thread data-race on slow connect path code: only permitted to
write to `req` on threads, as anything else causes data race
corruption.
There seemed be a small variety of other resource management bugs in
edge cases, which turned out to make this a lot larger than initially
expected.
Refs: https://github.com/libuv/libuv/pull/3598#issuecomment-1111513567
Although the change remapped the error code to the correct one, a lot of
code already depends on the incorrect one, so it's not worth the
breakage.
This reverts commit 04a35efe69.
Refs: https://github.com/nodejs/node/pull/42340
Signed-off-by: Darshan Sen <raisinten@gmail.com>
Replacement for the usage pattern where people use uv_cpu_info() as an
imperfect heuristic for determining the amount of parallelism that is
available to their programs.
Fixes#3493.
If we try to use uv_fs_rmdir on a read-only directory on Windows, it
internally calls _wrmdir, which sets _doserrno to ERROR_ACCESS_DENIED
and errno to EACCES. However, ERROR_ACCESS_DENIED is mapped to
UV_EPERM, so I believe it should be remapped to UV_EACCES.
Currently `LoadLibraryA` call first attempts to load the given DLL from
the application working directory before loading it from the system DLL
path. This may pose a security risk if an attacker is able to place a
malicious DLL into the application working directory as that DLL will
be loaded instead of the system DLL. This is especially dangerous if
the application is running with elevated privileges.
This changes the DLL loading to use `LoadLibraryExA` method with
`LOAD_LIBRARY_SEARCH_SYSTEM32` flag which restricts the DLL load
path to system DLL path, ignoring any DLLs in the application working
directory.