process-stdio.c
Go to the documentation of this file.
1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21 
22 #include <assert.h>
23 #include <io.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 
27 #include "uv.h"
28 #include "internal.h"
29 #include "handle-inl.h"
30 
31 
32 /*
33  * The `child_stdio_buffer` buffer has the following layout:
34  * int number_of_fds
35  * unsigned char crt_flags[number_of_fds]
36  * HANDLE os_handle[number_of_fds]
37  */
38 #define CHILD_STDIO_SIZE(count) \
39  (sizeof(int) + \
40  sizeof(unsigned char) * (count) + \
41  sizeof(uintptr_t) * (count))
42 
43 #define CHILD_STDIO_COUNT(buffer) \
44  *((unsigned int*) (buffer))
45 
46 #define CHILD_STDIO_CRT_FLAGS(buffer, fd) \
47  *((unsigned char*) (buffer) + sizeof(int) + fd)
48 
49 #define CHILD_STDIO_HANDLE(buffer, fd) \
50  *((HANDLE*) ((unsigned char*) (buffer) + \
51  sizeof(int) + \
52  sizeof(unsigned char) * \
53  CHILD_STDIO_COUNT((buffer)) + \
54  sizeof(HANDLE) * (fd)))
55 
56 
57 /* CRT file descriptor mode flags */
58 #define FOPEN 0x01
59 #define FEOFLAG 0x02
60 #define FCRLF 0x04
61 #define FPIPE 0x08
62 #define FNOINHERIT 0x10
63 #define FAPPEND 0x20
64 #define FDEV 0x40
65 #define FTEXT 0x80
66 
67 
68 /*
69  * Clear the HANDLE_FLAG_INHERIT flag from all HANDLEs that were inherited
70  * the parent process. Don't check for errors - the stdio handles may not be
71  * valid, or may be closed already. There is no guarantee that this function
72  * does a perfect job.
73  */
75  HANDLE handle;
76  STARTUPINFOW si;
77 
78  /* Make the windows stdio handles non-inheritable. */
79  handle = GetStdHandle(STD_INPUT_HANDLE);
80  if (handle != NULL && handle != INVALID_HANDLE_VALUE)
81  SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
82 
83  handle = GetStdHandle(STD_OUTPUT_HANDLE);
84  if (handle != NULL && handle != INVALID_HANDLE_VALUE)
85  SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
86 
87  handle = GetStdHandle(STD_ERROR_HANDLE);
88  if (handle != NULL && handle != INVALID_HANDLE_VALUE)
89  SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
90 
91  /* Make inherited CRT FDs non-inheritable. */
92  GetStartupInfoW(&si);
93  if (uv__stdio_verify(si.lpReserved2, si.cbReserved2))
94  uv__stdio_noinherit(si.lpReserved2);
95 }
96 
97 
99  uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
100  char pipe_name[64];
101  SECURITY_ATTRIBUTES sa;
102  DWORD server_access = 0;
103  DWORD client_access = 0;
104  HANDLE child_pipe = INVALID_HANDLE_VALUE;
105  int err;
106  int overlap;
107 
108  if (flags & UV_READABLE_PIPE) {
109  /* The server needs inbound access too, otherwise CreateNamedPipe() won't
110  * give us the FILE_READ_ATTRIBUTES permission. We need that to probe the
111  * state of the write buffer when we're trying to shutdown the pipe. */
112  server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND;
113  client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
114  }
115  if (flags & UV_WRITABLE_PIPE) {
116  server_access |= PIPE_ACCESS_INBOUND;
117  client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
118  }
119 
120  /* Create server pipe handle. */
122  server_pipe,
123  server_access,
124  pipe_name,
125  sizeof(pipe_name));
126  if (err)
127  goto error;
128 
129  /* Create child pipe handle. */
130  sa.nLength = sizeof sa;
131  sa.lpSecurityDescriptor = NULL;
132  sa.bInheritHandle = TRUE;
133 
134  overlap = server_pipe->ipc || (flags & UV_OVERLAPPED_PIPE);
135  child_pipe = CreateFileA(pipe_name,
136  client_access,
137  0,
138  &sa,
139  OPEN_EXISTING,
140  overlap ? FILE_FLAG_OVERLAPPED : 0,
141  NULL);
142  if (child_pipe == INVALID_HANDLE_VALUE) {
143  err = GetLastError();
144  goto error;
145  }
146 
147 #ifndef NDEBUG
148  /* Validate that the pipe was opened in the right mode. */
149  {
150  DWORD mode;
151  BOOL r = GetNamedPipeHandleState(child_pipe,
152  &mode,
153  NULL,
154  NULL,
155  NULL,
156  NULL,
157  0);
158  assert(r == TRUE);
159  assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
160  }
161 #endif
162 
163  /* Do a blocking ConnectNamedPipe. This should not block because we have both
164  * ends of the pipe created. */
165  if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
166  if (GetLastError() != ERROR_PIPE_CONNECTED) {
167  err = GetLastError();
168  goto error;
169  }
170  }
171 
172  /* The server end is now readable and/or writable. */
173  if (flags & UV_READABLE_PIPE)
174  server_pipe->flags |= UV_HANDLE_WRITABLE;
175  if (flags & UV_WRITABLE_PIPE)
176  server_pipe->flags |= UV_HANDLE_READABLE;
177 
178  *child_pipe_ptr = child_pipe;
179  return 0;
180 
181  error:
182  if (server_pipe->handle != INVALID_HANDLE_VALUE) {
183  uv_pipe_cleanup(loop, server_pipe);
184  }
185 
186  if (child_pipe != INVALID_HANDLE_VALUE) {
187  CloseHandle(child_pipe);
188  }
189 
190  return err;
191 }
192 
193 
194 static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
195  HANDLE current_process;
196 
197 
198  /* _get_osfhandle will sometimes return -2 in case of an error. This seems to
199  * happen when fd <= 2 and the process' corresponding stdio handle is set to
200  * NULL. Unfortunately DuplicateHandle will happily duplicate (HANDLE) -2, so
201  * this situation goes unnoticed until someone tries to use the duplicate.
202  * Therefore we filter out known-invalid handles here. */
203  if (handle == INVALID_HANDLE_VALUE ||
204  handle == NULL ||
205  handle == (HANDLE) -2) {
206  *dup = INVALID_HANDLE_VALUE;
207  return ERROR_INVALID_HANDLE;
208  }
209 
210  current_process = GetCurrentProcess();
211 
212  if (!DuplicateHandle(current_process,
213  handle,
214  current_process,
215  dup,
216  0,
217  TRUE,
218  DUPLICATE_SAME_ACCESS)) {
219  *dup = INVALID_HANDLE_VALUE;
220  return GetLastError();
221  }
222 
223  return 0;
224 }
225 
226 
227 static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
228  HANDLE handle;
229 
230  if (fd == -1) {
231  *dup = INVALID_HANDLE_VALUE;
232  return ERROR_INVALID_HANDLE;
233  }
234 
236  return uv__duplicate_handle(loop, handle, dup);
237 }
238 
239 
240 int uv__create_nul_handle(HANDLE* handle_ptr,
241  DWORD access) {
242  HANDLE handle;
243  SECURITY_ATTRIBUTES sa;
244 
245  sa.nLength = sizeof sa;
246  sa.lpSecurityDescriptor = NULL;
247  sa.bInheritHandle = TRUE;
248 
249  handle = CreateFileW(L"NUL",
250  access,
251  FILE_SHARE_READ | FILE_SHARE_WRITE,
252  &sa,
253  OPEN_EXISTING,
254  0,
255  NULL);
256  if (handle == INVALID_HANDLE_VALUE) {
257  return GetLastError();
258  }
259 
260  *handle_ptr = handle;
261  return 0;
262 }
263 
264 
267  BYTE** buffer_ptr) {
268  BYTE* buffer;
269  int count, i;
270  int err;
271 
272  count = options->stdio_count;
273 
274  if (count < 0 || count > 255) {
275  /* Only support FDs 0-255 */
276  return ERROR_NOT_SUPPORTED;
277  } else if (count < 3) {
278  /* There should always be at least 3 stdio handles. */
279  count = 3;
280  }
281 
282  /* Allocate the child stdio buffer */
284  if (buffer == NULL) {
285  return ERROR_OUTOFMEMORY;
286  }
287 
288  /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can clean
289  * up on failure. */
291  for (i = 0; i < count; i++) {
294  }
295 
296  for (i = 0; i < count; i++) {
297  uv_stdio_container_t fdopt;
298  if (i < options->stdio_count) {
299  fdopt = options->stdio[i];
300  } else {
301  fdopt.flags = UV_IGNORE;
302  }
303 
304  switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
306  case UV_IGNORE:
307  /* Starting a process with no stdin/stout/stderr can confuse it. So no
308  * matter what the user specified, we make sure the first three FDs are
309  * always open in their typical modes, e. g. stdin be readable and
310  * stdout/err should be writable. For FDs > 2, don't do anything - all
311  * handles in the stdio buffer are initialized with.
312  * INVALID_HANDLE_VALUE, which should be okay. */
313  if (i <= 2) {
314  DWORD access = (i == 0) ? FILE_GENERIC_READ :
315  FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
316 
318  access);
319  if (err)
320  goto error;
321 
323  }
324  break;
325 
326  case UV_CREATE_PIPE: {
327  /* Create a pair of two connected pipe ends; one end is turned into an
328  * uv_pipe_t for use by the parent. The other one is given to the
329  * child. */
330  uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;
331  HANDLE child_pipe = INVALID_HANDLE_VALUE;
332 
333  /* Create a new, connected pipe pair. stdio[i]. stream should point to
334  * an uninitialized, but not connected pipe handle. */
335  assert(fdopt.data.stream->type == UV_NAMED_PIPE);
336  assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
337  assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
338 
340  parent_pipe,
341  &child_pipe,
342  fdopt.flags);
343  if (err)
344  goto error;
345 
346  CHILD_STDIO_HANDLE(buffer, i) = child_pipe;
348  break;
349  }
350 
351  case UV_INHERIT_FD: {
352  /* Inherit a raw FD. */
353  HANDLE child_handle;
354 
355  /* Make an inheritable duplicate of the handle. */
356  err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle);
357  if (err) {
358  /* If fdopt. data. fd is not valid and fd <= 2, then ignore the
359  * error. */
360  if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {
363  break;
364  }
365  goto error;
366  }
367 
368  /* Figure out what the type is. */
369  switch (GetFileType(child_handle)) {
370  case FILE_TYPE_DISK:
372  break;
373 
374  case FILE_TYPE_PIPE:
376  break;
377 
378  case FILE_TYPE_CHAR:
379  case FILE_TYPE_REMOTE:
381  break;
382 
383  case FILE_TYPE_UNKNOWN:
384  if (GetLastError() != 0) {
385  err = GetLastError();
386  CloseHandle(child_handle);
387  goto error;
388  }
390  break;
391 
392  default:
393  assert(0);
394  return -1;
395  }
396 
397  CHILD_STDIO_HANDLE(buffer, i) = child_handle;
398  break;
399  }
400 
401  case UV_INHERIT_STREAM: {
402  /* Use an existing stream as the stdio handle for the child. */
403  HANDLE stream_handle, child_handle;
404  unsigned char crt_flags;
405  uv_stream_t* stream = fdopt.data.stream;
406 
407  /* Leech the handle out of the stream. */
408  if (stream->type == UV_TTY) {
409  stream_handle = ((uv_tty_t*) stream)->handle;
410  crt_flags = FOPEN | FDEV;
411  } else if (stream->type == UV_NAMED_PIPE &&
412  stream->flags & UV_HANDLE_CONNECTION) {
413  stream_handle = ((uv_pipe_t*) stream)->handle;
414  crt_flags = FOPEN | FPIPE;
415  } else {
417  crt_flags = 0;
418  }
419 
420  if (stream_handle == NULL ||
422  /* The handle is already closed, or not yet created, or the stream
423  * type is not supported. */
424  err = ERROR_NOT_SUPPORTED;
425  goto error;
426  }
427 
428  /* Make an inheritable copy of the handle. */
429  err = uv__duplicate_handle(loop, stream_handle, &child_handle);
430  if (err)
431  goto error;
432 
433  CHILD_STDIO_HANDLE(buffer, i) = child_handle;
434  CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags;
435  break;
436  }
437 
438  default:
439  assert(0);
440  return -1;
441  }
442  }
443 
444  *buffer_ptr = buffer;
445  return 0;
446 
447  error:
449  return err;
450 }
451 
452 
454  int i, count;
455 
457  for (i = 0; i < count; i++) {
458  HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
459  if (handle != INVALID_HANDLE_VALUE) {
460  CloseHandle(handle);
461  }
462  }
463 
464  uv__free(buffer);
465 }
466 
467 
469  int i, count;
470 
472  for (i = 0; i < count; i++) {
473  HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
474  if (handle != INVALID_HANDLE_VALUE) {
475  SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
476  }
477  }
478 }
479 
480 
481 int uv__stdio_verify(BYTE* buffer, WORD size) {
482  unsigned int count;
483 
484  /* Check the buffer pointer. */
485  if (buffer == NULL)
486  return 0;
487 
488  /* Verify that the buffer is at least big enough to hold the count. */
489  if (size < CHILD_STDIO_SIZE(0))
490  return 0;
491 
492  /* Verify if the count is within range. */
494  if (count > 256)
495  return 0;
496 
497  /* Verify that the buffer size is big enough to hold info for N FDs. */
498  if (size < CHILD_STDIO_SIZE(count))
499  return 0;
500 
501  return 1;
502 }
503 
504 
505 WORD uv__stdio_size(BYTE* buffer) {
506  return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)));
507 }
508 
509 
510 HANDLE uv__stdio_handle(BYTE* buffer, int fd) {
511  return CHILD_STDIO_HANDLE(buffer, fd);
512 }
UV_HANDLE_WRITABLE
@ UV_HANDLE_WRITABLE
Definition: uv-common.h:85
TRUE
const BOOL TRUE
Definition: undname.c:48
async_greeter_server_with_graceful_shutdown.loop
loop
Definition: async_greeter_server_with_graceful_shutdown.py:59
uv_process_options_s
Definition: uv.h:940
UV_HANDLE_PIPESERVER
@ UV_HANDLE_PIPESERVER
Definition: uv-common.h:111
uv__stdio_create
int uv__stdio_create(uv_loop_t *loop, const uv_process_options_t *options, BYTE **buffer_ptr)
Definition: process-stdio.c:265
CHILD_STDIO_HANDLE
#define CHILD_STDIO_HANDLE(buffer, fd)
Definition: process-stdio.c:49
UV_READABLE_PIPE
@ UV_READABLE_PIPE
Definition: uv.h:921
uv__duplicate_fd
static int uv__duplicate_fd(uv_loop_t *loop, int fd, HANDLE *dup)
Definition: process-stdio.c:227
uv__stdio_noinherit
void uv__stdio_noinherit(BYTE *buffer)
Definition: process-stdio.c:468
uv_disable_stdio_inheritance
void uv_disable_stdio_inheritance(void)
Definition: process-stdio.c:74
UV_IGNORE
@ UV_IGNORE
Definition: uv.h:911
uv__malloc
void * uv__malloc(size_t size)
Definition: uv-common.c:75
options
double_dict options[]
Definition: capstone_test.c:55
UV_HANDLE_CONNECTION
@ UV_HANDLE_CONNECTION
Definition: uv-common.h:75
uv_pipe_cleanup
void uv_pipe_cleanup(uv_loop_t *loop, uv_pipe_t *handle)
Definition: win/pipe.c:787
uv_tty_s
Definition: uv.h:704
error
grpc_error_handle error
Definition: retry_filter.cc:499
UV_OVERLAPPED_PIPE
@ UV_OVERLAPPED_PIPE
Definition: uv.h:928
error_ref_leak.err
err
Definition: error_ref_leak.py:35
uv__create_stdio_pipe_pair
static int uv__create_stdio_pipe_pair(uv_loop_t *loop, uv_pipe_t *server_pipe, HANDLE *child_pipe_ptr, unsigned int flags)
Definition: process-stdio.c:98
mode
const char int mode
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:135
stream_handle
Definition: benchmark-multi-accept.c:28
BOOL
int BOOL
Definition: undname.c:46
uv_stream_s
Definition: uv.h:491
CHILD_STDIO_COUNT
#define CHILD_STDIO_COUNT(buffer)
Definition: process-stdio.c:43
FPIPE
#define FPIPE
Definition: process-stdio.c:61
uv__stdio_handle
HANDLE uv__stdio_handle(BYTE *buffer, int fd)
Definition: process-stdio.c:510
UV_WRITABLE_PIPE
@ UV_WRITABLE_PIPE
Definition: uv.h:922
uv_stdio_container_s::flags
uv_stdio_flags flags
Definition: uv.h:932
uv_stdio_pipe_server
int uv_stdio_pipe_server(uv_loop_t *loop, uv_pipe_t *handle, DWORD access, char *name, size_t nameSize)
Definition: win/pipe.c:205
uv__stdio_verify
int uv__stdio_verify(BYTE *buffer, WORD size)
Definition: process-stdio.c:481
FOPEN
#define FOPEN
Definition: process-stdio.c:58
UV_INHERIT_FD
@ UV_INHERIT_FD
Definition: uv.h:913
UV_INHERIT_STREAM
@ UV_INHERIT_STREAM
Definition: uv.h:914
uv__free
void uv__free(void *ptr)
Definition: uv-common.c:81
buffer
char buffer[1024]
Definition: libuv/docs/code/idle-compute/main.c:8
uv_stdio_container_s
Definition: uv.h:931
uv__stdio_destroy
void uv__stdio_destroy(BYTE *buffer)
Definition: process-stdio.c:453
FDEV
#define FDEV
Definition: process-stdio.c:64
uv_stdio_container_s::fd
int fd
Definition: uv.h:936
CHILD_STDIO_CRT_FLAGS
#define CHILD_STDIO_CRT_FLAGS(buffer, fd)
Definition: process-stdio.c:46
uv_stdio_container_s::stream
uv_stream_t * stream
Definition: uv.h:935
uv__stdio_size
WORD uv__stdio_size(BYTE *buffer)
Definition: process-stdio.c:505
uv.h
UV_HANDLE_READABLE
@ UV_HANDLE_READABLE
Definition: uv-common.h:84
absl::flags_internal
Definition: abseil-cpp/absl/flags/commandlineflag.h:40
count
int * count
Definition: bloaty/third_party/googletest/googlemock/test/gmock_stress_test.cc:96
uv__get_osfhandle
static INLINE HANDLE uv__get_osfhandle(int fd)
Definition: handle-inl.h:166
L
lua_State * L
Definition: upb/upb/bindings/lua/main.c:35
fix_build_deps.r
r
Definition: fix_build_deps.py:491
INVALID_HANDLE_VALUE
#define INVALID_HANDLE_VALUE
Definition: bloaty/third_party/zlib/contrib/minizip/iowin32.c:21
uv_pipe_s::ipc
UV_HANDLE_FIELDS UV_STREAM_FIELDS int ipc
Definition: uv.h:760
uv_pipe_s
Definition: uv.h:757
UV_CREATE_PIPE
@ UV_CREATE_PIPE
Definition: uv.h:912
uv_stdio_container_s::data
union uv_stdio_container_s::@399 data
handle
static csh handle
Definition: test_arm_regression.c:16
uv__duplicate_handle
static int uv__duplicate_handle(uv_loop_t *loop, HANDLE handle, HANDLE *dup)
Definition: process-stdio.c:194
uv__create_nul_handle
int uv__create_nul_handle(HANDLE *handle_ptr, DWORD access)
Definition: process-stdio.c:240
uv_loop_s
Definition: uv.h:1767
internal.h
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
CHILD_STDIO_SIZE
#define CHILD_STDIO_SIZE(count)
Definition: process-stdio.c:38
access
Definition: bloaty/third_party/zlib/examples/zran.c:75
handle-inl.h
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
stream
voidpf stream
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:00:55