windows: improved handling of invalid FDs
If passed and invalid FD, _get_osfhandle() sets an error code through errno, not _doserrno. Hence we need to use SET_REQ_WIN32_ERROR insted of SET_REQ_RESULT. In debug builds, _get_osfhandle() also raises a superfluous assert. I implemented a wrapper that disables all asserts around the call to _get_osfhandle(). This fixes node.js unit tests test-fs-read-stream.js and test-listen-fd-ebadf.js.
This commit is contained in:
parent
4ce9c39dd8
commit
c0716b3d9f
@ -26,6 +26,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <crtdbg.h>
|
||||||
|
|
||||||
#include "uv.h"
|
#include "uv.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
@ -41,6 +42,32 @@ static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
|
|||||||
static uv_once_t uv_default_loop_init_guard_ = UV_ONCE_INIT;
|
static uv_once_t uv_default_loop_init_guard_ = UV_ONCE_INIT;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
/* Our crt debug report handler allows us to temporarily disable asserts */
|
||||||
|
/* just for the current thread. */
|
||||||
|
|
||||||
|
__declspec( thread ) int uv__crt_assert_enabled = TRUE;
|
||||||
|
|
||||||
|
static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) {
|
||||||
|
if (uv__crt_assert_enabled || report_type != _CRT_ASSERT)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (ret_val) {
|
||||||
|
/* Set ret_val to 0 to continue with normal execution. */
|
||||||
|
/* Set ret_val to 1 to trigger a breakpoint. */
|
||||||
|
|
||||||
|
if(IsDebuggerPresent())
|
||||||
|
*ret_val = 1;
|
||||||
|
else
|
||||||
|
*ret_val = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't call _CrtDbgReport. */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
|
static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
|
||||||
const wchar_t* function, const wchar_t * file, unsigned int line,
|
const wchar_t* function, const wchar_t * file, unsigned int line,
|
||||||
uintptr_t reserved) {
|
uintptr_t reserved) {
|
||||||
@ -59,6 +86,13 @@ static void uv_init(void) {
|
|||||||
_set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
|
_set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* We also need to setup our debug report handler because some CRT */
|
||||||
|
/* functions (eg _get_osfhandle) raise an assert when called with invalid */
|
||||||
|
/* FDs even though they return the proper error code in the release build. */
|
||||||
|
#ifdef _DEBUG
|
||||||
|
_CrtSetReportHook(uv__crt_dbg_report_handler);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Fetch winapi function pointers. This must be done first because other */
|
/* Fetch winapi function pointers. This must be done first because other */
|
||||||
/* intialization code might need these function pointers to be loaded. */
|
/* intialization code might need these function pointers to be loaded. */
|
||||||
uv_winapi_init();
|
uv_winapi_init();
|
||||||
|
|||||||
20
src/win/fs.c
20
src/win/fs.c
@ -34,6 +34,7 @@
|
|||||||
#include "uv.h"
|
#include "uv.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "req-inl.h"
|
#include "req-inl.h"
|
||||||
|
#include "handle-inl.h"
|
||||||
|
|
||||||
|
|
||||||
#define UV_FS_FREE_PATHS 0x0002
|
#define UV_FS_FREE_PATHS 0x0002
|
||||||
@ -548,9 +549,10 @@ void fs__read(uv_fs_t* req) {
|
|||||||
|
|
||||||
VERIFY_FD(fd, req);
|
VERIFY_FD(fd, req);
|
||||||
|
|
||||||
handle = (HANDLE) _get_osfhandle(fd);
|
handle = uv__get_osfhandle(fd);
|
||||||
|
|
||||||
if (handle == INVALID_HANDLE_VALUE) {
|
if (handle == INVALID_HANDLE_VALUE) {
|
||||||
SET_REQ_RESULT(req, -1);
|
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,9 +597,9 @@ void fs__write(uv_fs_t* req) {
|
|||||||
|
|
||||||
VERIFY_FD(fd, req);
|
VERIFY_FD(fd, req);
|
||||||
|
|
||||||
handle = (HANDLE) _get_osfhandle(fd);
|
handle = uv__get_osfhandle(fd);
|
||||||
if (handle == INVALID_HANDLE_VALUE) {
|
if (handle == INVALID_HANDLE_VALUE) {
|
||||||
SET_REQ_RESULT(req, -1);
|
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1004,7 +1006,7 @@ static void fs__fstat(uv_fs_t* req) {
|
|||||||
|
|
||||||
VERIFY_FD(fd, req);
|
VERIFY_FD(fd, req);
|
||||||
|
|
||||||
handle = (HANDLE) _get_osfhandle(fd);
|
handle = uv__get_osfhandle(fd);
|
||||||
|
|
||||||
if (handle == INVALID_HANDLE_VALUE) {
|
if (handle == INVALID_HANDLE_VALUE) {
|
||||||
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
|
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
|
||||||
@ -1037,7 +1039,7 @@ INLINE static void fs__sync_impl(uv_fs_t* req) {
|
|||||||
|
|
||||||
VERIFY_FD(fd, req);
|
VERIFY_FD(fd, req);
|
||||||
|
|
||||||
result = FlushFileBuffers((HANDLE) _get_osfhandle(fd)) ? 0 : -1;
|
result = FlushFileBuffers(uv__get_osfhandle(fd)) ? 0 : -1;
|
||||||
if (result == -1) {
|
if (result == -1) {
|
||||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||||
} else {
|
} else {
|
||||||
@ -1065,7 +1067,7 @@ static void fs__ftruncate(uv_fs_t* req) {
|
|||||||
|
|
||||||
VERIFY_FD(fd, req);
|
VERIFY_FD(fd, req);
|
||||||
|
|
||||||
handle = (HANDLE)_get_osfhandle(fd);
|
handle = uv__get_osfhandle(fd);
|
||||||
|
|
||||||
eof_info.EndOfFile.QuadPart = req->offset;
|
eof_info.EndOfFile.QuadPart = req->offset;
|
||||||
|
|
||||||
@ -1145,7 +1147,7 @@ static void fs__fchmod(uv_fs_t* req) {
|
|||||||
|
|
||||||
VERIFY_FD(fd, req);
|
VERIFY_FD(fd, req);
|
||||||
|
|
||||||
handle = (HANDLE) _get_osfhandle(fd);
|
handle = uv__get_osfhandle(fd);
|
||||||
|
|
||||||
nt_status = pNtQueryInformationFile(handle,
|
nt_status = pNtQueryInformationFile(handle,
|
||||||
&io_status,
|
&io_status,
|
||||||
@ -1226,7 +1228,7 @@ static void fs__futime(uv_fs_t* req) {
|
|||||||
HANDLE handle;
|
HANDLE handle;
|
||||||
VERIFY_FD(fd, req);
|
VERIFY_FD(fd, req);
|
||||||
|
|
||||||
handle = (HANDLE) _get_osfhandle(fd);
|
handle = uv__get_osfhandle(fd);
|
||||||
|
|
||||||
if (handle == INVALID_HANDLE_VALUE) {
|
if (handle == INVALID_HANDLE_VALUE) {
|
||||||
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
|
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
|
||||||
|
|||||||
@ -23,6 +23,7 @@
|
|||||||
#define UV_WIN_HANDLE_INL_H_
|
#define UV_WIN_HANDLE_INL_H_
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
#include "uv.h"
|
#include "uv.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
@ -161,4 +162,18 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INLINE static HANDLE uv__get_osfhandle(int fd)
|
||||||
|
{
|
||||||
|
/* _get_osfhandle() raises an assert in debug builds if the FD is invalid. */
|
||||||
|
/* But it also correctly checks the FD and returns INVALID_HANDLE_VALUE */
|
||||||
|
/* for invalid FDs in release builds (or if you let the assert continue). */
|
||||||
|
/* So this wrapper function disables asserts when calling _get_osfhandle. */
|
||||||
|
|
||||||
|
HANDLE handle;
|
||||||
|
UV_BEGIN_DISABLE_CRT_ASSERT();
|
||||||
|
handle = (HANDLE) _get_osfhandle(fd);
|
||||||
|
UV_END_DISABLE_CRT_ASSERT();
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* UV_WIN_HANDLE_INL_H_ */
|
#endif /* UV_WIN_HANDLE_INL_H_ */
|
||||||
|
|||||||
@ -36,7 +36,7 @@ uv_handle_type uv_guess_handle(uv_file file) {
|
|||||||
return UV_UNKNOWN_HANDLE;
|
return UV_UNKNOWN_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle = (HANDLE) _get_osfhandle(file);
|
handle = uv__get_osfhandle(file);
|
||||||
|
|
||||||
switch (GetFileType(handle)) {
|
switch (GetFileType(handle)) {
|
||||||
case FILE_TYPE_CHAR:
|
case FILE_TYPE_CHAR:
|
||||||
|
|||||||
@ -35,6 +35,25 @@
|
|||||||
# define INLINE inline
|
# define INLINE inline
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
extern __declspec( thread ) int uv__crt_assert_enabled;
|
||||||
|
|
||||||
|
#define UV_BEGIN_DISABLE_CRT_ASSERT() \
|
||||||
|
{ \
|
||||||
|
int uv__saved_crt_assert_enabled = uv__crt_assert_enabled; \
|
||||||
|
uv__crt_assert_enabled = FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
#define UV_END_DISABLE_CRT_ASSERT() \
|
||||||
|
uv__crt_assert_enabled = uv__saved_crt_assert_enabled; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define UV_BEGIN_DISABLE_CRT_ASSERT()
|
||||||
|
#define UV_END_DISABLE_CRT_ASSERT()
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handles
|
* Handles
|
||||||
* (also see handle-inl.h)
|
* (also see handle-inl.h)
|
||||||
|
|||||||
@ -1727,7 +1727,7 @@ static void eof_timer_close_cb(uv_handle_t* handle) {
|
|||||||
|
|
||||||
|
|
||||||
int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
|
int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
|
||||||
HANDLE os_handle = (HANDLE)_get_osfhandle(file);
|
HANDLE os_handle = uv__get_osfhandle(file);
|
||||||
|
|
||||||
if (os_handle == INVALID_HANDLE_VALUE ||
|
if (os_handle == INVALID_HANDLE_VALUE ||
|
||||||
uv_set_pipe_handle(pipe->loop, pipe, os_handle, 0) == -1) {
|
uv_set_pipe_handle(pipe->loop, pipe, os_handle, 0) == -1) {
|
||||||
|
|||||||
@ -482,7 +482,7 @@ static int uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
|
|||||||
|
|
||||||
|
|
||||||
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
|
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
|
||||||
return uv_poll_init_socket(loop, handle, (SOCKET) _get_osfhandle(fd));
|
return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include "uv.h"
|
#include "uv.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
#include "handle-inl.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -230,7 +231,7 @@ static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
|
|||||||
return ERROR_INVALID_HANDLE;
|
return ERROR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle = (HANDLE) _get_osfhandle(fd);
|
handle = uv__get_osfhandle(fd);
|
||||||
return uv__duplicate_handle(loop, handle, dup);
|
return uv__duplicate_handle(loop, handle, dup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user