linux: fix thread cancellation fd leak
Same as the previous commit but this time for Linux. Specifically, the glibc close() wrapper is a cancellation point; the thread is unwound when close() is called when the thread is in the "cancel" state. That's according to spec and therefore arguably less severe than MacOS's "EINTR without actually closing" behavior but we can avoid the file descriptor leak altogether by sidestepping glibc and making the system call directly. Musl libc is unaffected, its close() wrapper doesn't check the cancel state. PR-URL: https://github.com/libuv/libuv/pull/2291 Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
parent
9063c27f92
commit
2138dd2f08
@ -88,6 +88,10 @@
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
static int uv__run_pending(uv_loop_t* loop);
|
||||
|
||||
/* Verify that uv_buf_t is ABI-compatible with struct iovec. */
|
||||
@ -513,6 +517,10 @@ skip:
|
||||
/* close() on macos has the "interesting" quirk that it fails with EINTR
|
||||
* without closing the file descriptor when a thread is in the cancel state.
|
||||
* That's why libuv calls close$NOCANCEL() instead.
|
||||
*
|
||||
* glibc on linux has a similar issue: close() is a cancellation point and
|
||||
* will unwind the thread when it's in the cancel state. Work around that
|
||||
* by making the system call directly. Musl libc is unaffected.
|
||||
*/
|
||||
int uv__close_nocancel(int fd) {
|
||||
#if defined(__APPLE__)
|
||||
@ -521,6 +529,8 @@ int uv__close_nocancel(int fd) {
|
||||
extern int close$NOCANCEL(int);
|
||||
return close$NOCANCEL(fd);
|
||||
#pragma GCC diagnostic pop
|
||||
#elif defined(__linux__)
|
||||
return syscall(SYS_close, fd);
|
||||
#else
|
||||
return close(fd);
|
||||
#endif
|
||||
|
||||
Loading…
Reference in New Issue
Block a user