diff --git a/src/win/core.c b/src/win/core.c index ddeb0bc7..e1a77655 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "uv.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; +#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, const wchar_t* function, const wchar_t * file, unsigned int line, uintptr_t reserved) { @@ -59,6 +86,13 @@ static void uv_init(void) { _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler); #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 */ /* intialization code might need these function pointers to be loaded. */ uv_winapi_init(); diff --git a/src/win/fs.c b/src/win/fs.c index e3e11c77..c4182758 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -34,6 +34,7 @@ #include "uv.h" #include "internal.h" #include "req-inl.h" +#include "handle-inl.h" #define UV_FS_FREE_PATHS 0x0002 @@ -548,9 +549,10 @@ void fs__read(uv_fs_t* req) { VERIFY_FD(fd, req); - handle = (HANDLE) _get_osfhandle(fd); + handle = uv__get_osfhandle(fd); + if (handle == INVALID_HANDLE_VALUE) { - SET_REQ_RESULT(req, -1); + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); return; } @@ -595,9 +597,9 @@ void fs__write(uv_fs_t* req) { VERIFY_FD(fd, req); - handle = (HANDLE) _get_osfhandle(fd); + handle = uv__get_osfhandle(fd); if (handle == INVALID_HANDLE_VALUE) { - SET_REQ_RESULT(req, -1); + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); return; } @@ -1004,7 +1006,7 @@ static void fs__fstat(uv_fs_t* req) { VERIFY_FD(fd, req); - handle = (HANDLE) _get_osfhandle(fd); + handle = uv__get_osfhandle(fd); if (handle == INVALID_HANDLE_VALUE) { 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); - result = FlushFileBuffers((HANDLE) _get_osfhandle(fd)) ? 0 : -1; + result = FlushFileBuffers(uv__get_osfhandle(fd)) ? 0 : -1; if (result == -1) { SET_REQ_WIN32_ERROR(req, GetLastError()); } else { @@ -1065,7 +1067,7 @@ static void fs__ftruncate(uv_fs_t* req) { VERIFY_FD(fd, req); - handle = (HANDLE)_get_osfhandle(fd); + handle = uv__get_osfhandle(fd); eof_info.EndOfFile.QuadPart = req->offset; @@ -1145,7 +1147,7 @@ static void fs__fchmod(uv_fs_t* req) { VERIFY_FD(fd, req); - handle = (HANDLE) _get_osfhandle(fd); + handle = uv__get_osfhandle(fd); nt_status = pNtQueryInformationFile(handle, &io_status, @@ -1226,7 +1228,7 @@ static void fs__futime(uv_fs_t* req) { HANDLE handle; VERIFY_FD(fd, req); - handle = (HANDLE) _get_osfhandle(fd); + handle = uv__get_osfhandle(fd); if (handle == INVALID_HANDLE_VALUE) { SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); diff --git a/src/win/handle-inl.h b/src/win/handle-inl.h index 3eef10c4..5776eb7f 100644 --- a/src/win/handle-inl.h +++ b/src/win/handle-inl.h @@ -23,6 +23,7 @@ #define UV_WIN_HANDLE_INL_H_ #include +#include #include "uv.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_ */ diff --git a/src/win/handle.c b/src/win/handle.c index 26848200..72b49d97 100644 --- a/src/win/handle.c +++ b/src/win/handle.c @@ -36,7 +36,7 @@ uv_handle_type uv_guess_handle(uv_file file) { return UV_UNKNOWN_HANDLE; } - handle = (HANDLE) _get_osfhandle(file); + handle = uv__get_osfhandle(file); switch (GetFileType(handle)) { case FILE_TYPE_CHAR: diff --git a/src/win/internal.h b/src/win/internal.h index 6a4fb46b..cf6c8584 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -35,6 +35,25 @@ # define INLINE inline #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 * (also see handle-inl.h) diff --git a/src/win/pipe.c b/src/win/pipe.c index a57a7751..f3d3110d 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -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) { - HANDLE os_handle = (HANDLE)_get_osfhandle(file); + HANDLE os_handle = uv__get_osfhandle(file); if (os_handle == INVALID_HANDLE_VALUE || uv_set_pipe_handle(pipe->loop, pipe, os_handle, 0) == -1) { diff --git a/src/win/poll.c b/src/win/poll.c index 4ba91e2a..75351afd 100644 --- a/src/win/poll.c +++ b/src/win/poll.c @@ -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) { - return uv_poll_init_socket(loop, handle, (SOCKET) _get_osfhandle(fd)); + return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd)); } diff --git a/src/win/process-stdio.c b/src/win/process-stdio.c index 44a67fd1..5757764b 100644 --- a/src/win/process-stdio.c +++ b/src/win/process-stdio.c @@ -26,6 +26,7 @@ #include "uv.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; } - handle = (HANDLE) _get_osfhandle(fd); + handle = uv__get_osfhandle(fd); return uv__duplicate_handle(loop, handle, dup); }