Skip to content
This repository was archived by the owner on Nov 21, 2018. It is now read-only.

Commit c0716b3

Browse files
orangemochapiscisaureus
authored andcommitted
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.
1 parent 4ce9c39 commit c0716b3

File tree

8 files changed

+84
-13
lines changed

8 files changed

+84
-13
lines changed

src/win/core.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <stdio.h>
2727
#include <stdlib.h>
2828
#include <string.h>
29+
#include <crtdbg.h>
2930

3031
#include "uv.h"
3132
#include "internal.h"
@@ -41,6 +42,32 @@ static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
4142
static uv_once_t uv_default_loop_init_guard_ = UV_ONCE_INIT;
4243

4344

45+
#ifdef _DEBUG
46+
/* Our crt debug report handler allows us to temporarily disable asserts */
47+
/* just for the current thread. */
48+
49+
__declspec( thread ) int uv__crt_assert_enabled = TRUE;
50+
51+
static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) {
52+
if (uv__crt_assert_enabled || report_type != _CRT_ASSERT)
53+
return FALSE;
54+
55+
if (ret_val) {
56+
/* Set ret_val to 0 to continue with normal execution. */
57+
/* Set ret_val to 1 to trigger a breakpoint. */
58+
59+
if(IsDebuggerPresent())
60+
*ret_val = 1;
61+
else
62+
*ret_val = 0;
63+
}
64+
65+
/* Don't call _CrtDbgReport. */
66+
return TRUE;
67+
}
68+
#endif
69+
70+
4471
static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
4572
const wchar_t* function, const wchar_t * file, unsigned int line,
4673
uintptr_t reserved) {
@@ -59,6 +86,13 @@ static void uv_init(void) {
5986
_set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
6087
#endif
6188

89+
/* We also need to setup our debug report handler because some CRT */
90+
/* functions (eg _get_osfhandle) raise an assert when called with invalid */
91+
/* FDs even though they return the proper error code in the release build. */
92+
#ifdef _DEBUG
93+
_CrtSetReportHook(uv__crt_dbg_report_handler);
94+
#endif
95+
6296
/* Fetch winapi function pointers. This must be done first because other */
6397
/* intialization code might need these function pointers to be loaded. */
6498
uv_winapi_init();

src/win/fs.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "uv.h"
3535
#include "internal.h"
3636
#include "req-inl.h"
37+
#include "handle-inl.h"
3738

3839

3940
#define UV_FS_FREE_PATHS 0x0002
@@ -548,9 +549,10 @@ void fs__read(uv_fs_t* req) {
548549

549550
VERIFY_FD(fd, req);
550551

551-
handle = (HANDLE) _get_osfhandle(fd);
552+
handle = uv__get_osfhandle(fd);
553+
552554
if (handle == INVALID_HANDLE_VALUE) {
553-
SET_REQ_RESULT(req, -1);
555+
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
554556
return;
555557
}
556558

@@ -595,9 +597,9 @@ void fs__write(uv_fs_t* req) {
595597

596598
VERIFY_FD(fd, req);
597599

598-
handle = (HANDLE) _get_osfhandle(fd);
600+
handle = uv__get_osfhandle(fd);
599601
if (handle == INVALID_HANDLE_VALUE) {
600-
SET_REQ_RESULT(req, -1);
602+
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
601603
return;
602604
}
603605

@@ -1004,7 +1006,7 @@ static void fs__fstat(uv_fs_t* req) {
10041006

10051007
VERIFY_FD(fd, req);
10061008

1007-
handle = (HANDLE) _get_osfhandle(fd);
1009+
handle = uv__get_osfhandle(fd);
10081010

10091011
if (handle == INVALID_HANDLE_VALUE) {
10101012
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
@@ -1037,7 +1039,7 @@ INLINE static void fs__sync_impl(uv_fs_t* req) {
10371039

10381040
VERIFY_FD(fd, req);
10391041

1040-
result = FlushFileBuffers((HANDLE) _get_osfhandle(fd)) ? 0 : -1;
1042+
result = FlushFileBuffers(uv__get_osfhandle(fd)) ? 0 : -1;
10411043
if (result == -1) {
10421044
SET_REQ_WIN32_ERROR(req, GetLastError());
10431045
} else {
@@ -1065,7 +1067,7 @@ static void fs__ftruncate(uv_fs_t* req) {
10651067

10661068
VERIFY_FD(fd, req);
10671069

1068-
handle = (HANDLE)_get_osfhandle(fd);
1070+
handle = uv__get_osfhandle(fd);
10691071

10701072
eof_info.EndOfFile.QuadPart = req->offset;
10711073

@@ -1145,7 +1147,7 @@ static void fs__fchmod(uv_fs_t* req) {
11451147

11461148
VERIFY_FD(fd, req);
11471149

1148-
handle = (HANDLE) _get_osfhandle(fd);
1150+
handle = uv__get_osfhandle(fd);
11491151

11501152
nt_status = pNtQueryInformationFile(handle,
11511153
&io_status,
@@ -1226,7 +1228,7 @@ static void fs__futime(uv_fs_t* req) {
12261228
HANDLE handle;
12271229
VERIFY_FD(fd, req);
12281230

1229-
handle = (HANDLE) _get_osfhandle(fd);
1231+
handle = uv__get_osfhandle(fd);
12301232

12311233
if (handle == INVALID_HANDLE_VALUE) {
12321234
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);

src/win/handle-inl.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#define UV_WIN_HANDLE_INL_H_
2424

2525
#include <assert.h>
26+
#include <io.h>
2627

2728
#include "uv.h"
2829
#include "internal.h"
@@ -161,4 +162,18 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) {
161162
}
162163
}
163164

165+
INLINE static HANDLE uv__get_osfhandle(int fd)
166+
{
167+
/* _get_osfhandle() raises an assert in debug builds if the FD is invalid. */
168+
/* But it also correctly checks the FD and returns INVALID_HANDLE_VALUE */
169+
/* for invalid FDs in release builds (or if you let the assert continue). */
170+
/* So this wrapper function disables asserts when calling _get_osfhandle. */
171+
172+
HANDLE handle;
173+
UV_BEGIN_DISABLE_CRT_ASSERT();
174+
handle = (HANDLE) _get_osfhandle(fd);
175+
UV_END_DISABLE_CRT_ASSERT();
176+
return handle;
177+
}
178+
164179
#endif /* UV_WIN_HANDLE_INL_H_ */

src/win/handle.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ uv_handle_type uv_guess_handle(uv_file file) {
3636
return UV_UNKNOWN_HANDLE;
3737
}
3838

39-
handle = (HANDLE) _get_osfhandle(file);
39+
handle = uv__get_osfhandle(file);
4040

4141
switch (GetFileType(handle)) {
4242
case FILE_TYPE_CHAR:

src/win/internal.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,25 @@
3535
# define INLINE inline
3636
#endif
3737

38+
39+
#ifdef _DEBUG
40+
extern __declspec( thread ) int uv__crt_assert_enabled;
41+
42+
#define UV_BEGIN_DISABLE_CRT_ASSERT() \
43+
{ \
44+
int uv__saved_crt_assert_enabled = uv__crt_assert_enabled; \
45+
uv__crt_assert_enabled = FALSE;
46+
47+
48+
#define UV_END_DISABLE_CRT_ASSERT() \
49+
uv__crt_assert_enabled = uv__saved_crt_assert_enabled; \
50+
}
51+
52+
#else
53+
#define UV_BEGIN_DISABLE_CRT_ASSERT()
54+
#define UV_END_DISABLE_CRT_ASSERT()
55+
#endif
56+
3857
/*
3958
* Handles
4059
* (also see handle-inl.h)

src/win/pipe.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1727,7 +1727,7 @@ static void eof_timer_close_cb(uv_handle_t* handle) {
17271727

17281728

17291729
int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
1730-
HANDLE os_handle = (HANDLE)_get_osfhandle(file);
1730+
HANDLE os_handle = uv__get_osfhandle(file);
17311731

17321732
if (os_handle == INVALID_HANDLE_VALUE ||
17331733
uv_set_pipe_handle(pipe->loop, pipe, os_handle, 0) == -1) {

src/win/poll.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ static int uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
482482

483483

484484
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
485-
return uv_poll_init_socket(loop, handle, (SOCKET) _get_osfhandle(fd));
485+
return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd));
486486
}
487487

488488

src/win/process-stdio.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include "uv.h"
2828
#include "internal.h"
29+
#include "handle-inl.h"
2930

3031

3132
/*
@@ -230,7 +231,7 @@ static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
230231
return ERROR_INVALID_HANDLE;
231232
}
232233

233-
handle = (HANDLE) _get_osfhandle(fd);
234+
handle = uv__get_osfhandle(fd);
234235
return uv__duplicate_handle(loop, handle, dup);
235236
}
236237

0 commit comments

Comments
 (0)