Skip to content

Commit

Permalink
win,pipe: fix IPC pipe deadlock
Browse files Browse the repository at this point in the history
This fixes a bug where IPC pipe communication would deadlock when both
ends of the pipe are written to simultaneously, and the kernel pipe
buffer has already been filled up by earlier writes.

The root cause of the deadlock is that, while writes to an IPC pipe are
generally asynchronous, the IPC frame header is written synchronously.
So when both ends of the pipe are sending a frame header at the same
time, neither will read data off the pipe, causing both header writes
to block indefinitely.

Additionally, this patch somewhat reduces the spaghetti level in
win/pipe.c.

Fixes: #1099
Refs: nodejs/node#7657
Refs: electron/electron#10107
Refs: parcel-bundler/parcel#637
Refs: parcel-bundler/parcel#900
Refs: parcel-bundler/parcel#1137
  • Loading branch information
piscisaureus committed May 25, 2018
1 parent 4d24508 commit 45f6958
Show file tree
Hide file tree
Showing 7 changed files with 419 additions and 434 deletions.
24 changes: 12 additions & 12 deletions include/uv-win.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,11 +368,10 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
} u; \
struct uv_req_s* next_req;

#define UV_WRITE_PRIVATE_FIELDS \
int coalesced; /* This ABI change will be un-done in a later commit. */ \
int ipc_header; \
uv_buf_t write_buffer; \
HANDLE event_handle; \
#define UV_WRITE_PRIVATE_FIELDS \
int coalesced; \
uv_buf_t write_buffer; \
HANDLE event_handle; \
HANDLE wait_handle;

#define UV_CONNECT_PRIVATE_FIELDS \
Expand Down Expand Up @@ -460,13 +459,14 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);

#define uv_pipe_connection_fields \
uv_timer_t* eof_timer; \
uv_write_t ipc_header_write_req; \
int ipc_pid; \
uint64_t remaining_ipc_rawdata_bytes; \
struct { \
void* queue[2]; \
int queue_len; \
} pending_ipc_info; \
uv_write_t dummy; /* TODO: retained for ABI compat; remove this in v2.x. */ \
DWORD ipc_remote_pid; \
union { \
uint32_t payload_remaining; \
uint64_t dummy; /* TODO: retained for ABI compat; remove this in v2.x. */ \
} ipc_data_frame; \
void* ipc_xfer_queue[2]; \
int ipc_xfer_queue_length; \
uv_write_t* non_overlapped_writes_tail; \
CRITICAL_SECTION readfile_thread_lock; \
volatile HANDLE readfile_thread_handle;
Expand Down
27 changes: 14 additions & 13 deletions src/win/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,9 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled;

typedef struct {
WSAPROTOCOL_INFOW socket_info;
int delayed_error;
} uv__ipc_socket_info_ex;
uint32_t delayed_error;
uint32_t flags; /* Either zero or UV_HANDLE_CONNECTION. */
} uv__ipc_socket_xfer_info_t;

int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
Expand All @@ -149,11 +150,10 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);

int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
int tcp_connection);

int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
LPWSAPROTOCOL_INFOW protocol_info);
int uv__tcp_xfer_export(uv_tcp_t* handle,
int pid,
uv__ipc_socket_xfer_info_t* xfer_info);
int uv__tcp_xfer_import(uv_tcp_t* tcp, uv__ipc_socket_xfer_info_t* xfer_info);


/*
Expand All @@ -178,11 +178,13 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client);
int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb);
void uv__pipe_read_stop(uv_pipe_t* handle);
int uv_pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
int uv_pipe_write2(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle,
uv_write_cb cb);
int uv__pipe_write(uv_loop_t* loop,
uv_write_t* req,
uv_pipe_t* handle,
const uv_buf_t bufs[],
size_t nbufs,
uv_stream_t* send_handle,
uv_write_cb cb);

void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_req_t* req);
Expand Down Expand Up @@ -329,7 +331,6 @@ void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle);
void uv__util_init(void);

uint64_t uv__hrtime(double scale);
int uv_current_pid(void);
__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
int uv__getpwuid_r(uv_passwd_t* pwd);
int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8);
Expand Down
Loading

0 comments on commit 45f6958

Please sign in to comment.