@@ -276,6 +276,27 @@ rb_update_max_fd(int fd)
276276void
277277rb_maygvl_fd_fix_cloexec (int fd )
278278{
279+ #ifdef _WIN32
280+ /* Use the dedicated rb_w32_set_cloexec helper instead of the fcntl
281+ * path below, so that both the OS-level HANDLE_FLAG_INHERIT bit and
282+ * the CRT _osfile FNOINHERIT bit are kept in sync. The standard
283+ * handles (0, 1, 2) stay inheritable, while every other fd is made
284+ * non-inheritable (close-on-exec) by default. This matches the
285+ * assumption elsewhere (notably the lpReserved2 fd-inheritance
286+ * machinery) that a fd is inherited by a child only when
287+ * close_on_exec was explicitly cleared. */
288+ if (fd <= 2 ) {
289+ if (rb_w32_set_cloexec (fd , FALSE) != 0 )
290+ rb_bug ("rb_maygvl_fd_fix_cloexec: rb_w32_set_cloexec(%d, FALSE) failed: %s" ,
291+ fd , strerror (errno ));
292+ }
293+ else {
294+ if (rb_w32_set_cloexec (fd , TRUE) != 0 )
295+ rb_bug ("rb_maygvl_fd_fix_cloexec: rb_w32_set_cloexec(%d, TRUE) failed: %s" ,
296+ fd , strerror (errno ));
297+ }
298+ return ;
299+ #endif
279300 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
280301#if defined(HAVE_FCNTL ) && defined(F_GETFD ) && defined(F_SETFD ) && defined(FD_CLOEXEC )
281302 int flags , flags2 , ret ;
@@ -303,6 +324,13 @@ rb_fd_fix_cloexec(int fd)
303324 rb_update_max_fd (fd );
304325}
305326
327+ /* License: Ruby's */
328+ int
329+ rb_get_max_fd (void )
330+ {
331+ return (int )max_file_descriptor ;
332+ }
333+
306334/* this is only called once */
307335static int
308336rb_fix_detect_o_cloexec (int fd )
@@ -7705,18 +7733,35 @@ pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
77057733# if defined(HAVE_SPAWNVE )
77067734 if (eargp -> envp_str ) envp = (char * * )RSTRING_PTR (eargp -> envp_str );
77077735# endif
7708- while ((pid = DO_SPAWN (cmd , args , envp )) < 0 ) {
7709- /* exec failed */
7710- switch (e = errno ) {
7711- case EAGAIN :
7736+ # if defined(_WIN32 )
7737+ /* On Windows, spawn through the inherit-table path so that
7738+ * close_on_exec = false fds (and any explicit fd_dup2 redirects
7739+ * set up above) propagate to the child via lpReserved2. */
7740+ struct rb_w32_inherit_actions actions ;
7741+ rb_w32_build_inherit_actions (eargp , & actions );
7742+ if (args ) {
7743+ pid = rb_w32_uaspawn_inherit (P_NOWAIT ,
7744+ cmd , args , 0 , CP_UTF8 , & actions );
7745+ }
7746+ else {
7747+ pid = rb_w32_uspawn_inherit (P_NOWAIT , cmd , NULL ,
7748+ CP_UTF8 , & actions );
7749+ }
7750+ rb_w32_free_inherit_actions (& actions );
7751+ # else
7752+ while ((pid = DO_SPAWN (cmd , args , envp )) < 0 ) {
7753+ /* exec failed */
7754+ switch (e = errno ) {
7755+ case EAGAIN :
77127756# if EWOULDBLOCK != EAGAIN
7713- case EWOULDBLOCK :
7757+ case EWOULDBLOCK :
77147758# endif
7715- rb_thread_sleep (1 );
7716- continue ;
7759+ rb_thread_sleep (1 );
7760+ continue ;
7761+ }
7762+ break ;
77177763 }
7718- break ;
7719- }
7764+ # endif
77207765 if (eargp )
77217766 rb_execarg_run_options (sargp , NULL , NULL , 0 );
77227767# endif
@@ -7738,9 +7783,7 @@ pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
77387783
77397784 /* parent */
77407785 if (pid < 0 ) {
7741- # if defined(HAVE_WORKING_FORK )
77427786 e = errno ;
7743- # endif
77447787 close (arg .pair [0 ]);
77457788 close (arg .pair [1 ]);
77467789 if ((fmode & (FMODE_READABLE |FMODE_WRITABLE )) == (FMODE_READABLE |FMODE_WRITABLE )) {
0 commit comments