From ade693024195716504416a2bbf3c87df05fb2022 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 14 Jun 2012 01:19:52 +0200 Subject: [PATCH] windows: implement uv_disable_stdio_inheritance --- include/uv.h | 16 ++++++++++++ src/unix/core.c | 4 +++ src/win/internal.h | 1 + src/win/process-stdio.c | 54 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+) diff --git a/include/uv.h b/include/uv.h index e52ae643..8bd387ac 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1580,6 +1580,22 @@ UV_EXTERN uint64_t uv_get_total_memory(void); UV_EXTERN extern uint64_t uv_hrtime(void); +/* + * Disables inheritance for file descriptors / handles that this process + * inherited from its parent. The effect is that child processes spawned by + * this proces don't accidently inherit these handles. + * + * It is recommended to call this function as early in your program as possible, + * before the inherited file descriptors can be closed or duplicated. + * + * Note that this function works on a best-effort basis: there is no guarantee + * that libuv can discover all file descriptors that were inherited. In general + * it does a better job on Windows than it does on unix. + * + * TODO(bb): insert snarky remark to annoy bnoordhuis and the folks at joyent. + */ +UV_EXTERN void uv_disable_stdio_inheritance(void); + /* * Opens a shared library. The filename is in utf-8. Returns 0 on success and * -1 on error. Call `uv_dlerror(uv_lib_t*)` to get the error message. diff --git a/src/unix/core.c b/src/unix/core.c index 766da526..b1d47ed0 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -586,6 +586,10 @@ uv_err_t uv_chdir(const char* dir) { } +void uv_disable_stdio_inheritance(void) { +} + + static void uv__io_set_cb(uv__io_t* handle, uv__io_cb cb) { union { void* data; uv__io_cb cb; } u; u.cb = cb; diff --git a/src/win/internal.h b/src/win/internal.h index b5dadb91..30d9e8c5 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -286,6 +286,7 @@ int uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options, BYTE** buffer_ptr); void uv__stdio_destroy(BYTE* buffer); void uv__stdio_noinherit(BYTE* buffer); +int uv__stdio_verify(BYTE* buffer, WORD size); WORD uv__stdio_size(BYTE* buffer); HANDLE uv__stdio_handle(BYTE* buffer, int fd); diff --git a/src/win/process-stdio.c b/src/win/process-stdio.c index ad998aee..2ae9a143 100644 --- a/src/win/process-stdio.c +++ b/src/win/process-stdio.c @@ -64,6 +64,36 @@ #define FTEXT 0x80 +/* + * Clear the HANDLE_FLAG_INHERIT flag from all HANDLEs that were inherited + * the parent process. Don't check for errors - the stdio handles may not be + * valid, or may be closed already. There is no guarantee that this function + * does a perfect job. + */ +void uv_disable_stdio_inheritance(void) { + HANDLE handle; + STARTUPINFOW si; + + /* Make the windows stdio handles non-inheritable. */ + handle = GetStdHandle(STD_INPUT_HANDLE); + if (handle != NULL && handle != INVALID_HANDLE_VALUE) + SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); + + handle = GetStdHandle(STD_OUTPUT_HANDLE); + if (handle != NULL && handle != INVALID_HANDLE_VALUE) + SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); + + handle = GetStdHandle(STD_ERROR_HANDLE); + if (handle != NULL && handle != INVALID_HANDLE_VALUE) + SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); + + /* Make inherited CRT FDs non-inheritable. */ + GetStartupInfoW(&si); + if (uv__stdio_verify(si.lpReserved2, si.cbReserved2)) + uv__stdio_noinherit(si.lpReserved2); +} + + static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) { char pipe_name[64]; @@ -415,6 +445,30 @@ void uv__stdio_noinherit(BYTE* buffer) { } +int uv__stdio_verify(BYTE* buffer, WORD size) { + unsigned int count; + + /* Check the buffer pointer. */ + if (buffer == NULL) + return 0; + + /* Verify that the buffer is at least big enough to hold the count. */ + if (size < CHILD_STDIO_SIZE(0)) + return 0; + + /* Verify if the count is within range. */ + count = CHILD_STDIO_COUNT(buffer); + if (count > 256) + return 0; + + /* Verify that the buffer size is big enough to hold info for N FDs. */ + if (size < CHILD_STDIO_SIZE(count)) + return 0; + + return 1; +} + + WORD uv__stdio_size(BYTE* buffer) { return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer))); }