glib/win32: fix passing same fd for stdout & stderr spawn

Delay closing the FDs after all input FDs are duped.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André Lureau 2022-02-04 12:30:10 +04:00
parent 2d35c57718
commit e05227371d
3 changed files with 12 additions and 21 deletions

View File

@ -154,7 +154,7 @@ protect_wargv (gint argc,
} }
static int static int
checked_dup2 (int oldfd, int newfd, int report_fd, gboolean close_old) checked_dup2 (int oldfd, int newfd, int report_fd)
{ {
if (oldfd == newfd) if (oldfd == newfd)
return newfd; return newfd;
@ -162,9 +162,6 @@ checked_dup2 (int oldfd, int newfd, int report_fd, gboolean close_old)
if (dup2 (oldfd, newfd) == -1) if (dup2 (oldfd, newfd) == -1)
write_err_and_exit (report_fd, CHILD_DUP_FAILED); write_err_and_exit (report_fd, CHILD_DUP_FAILED);
if (close_old)
close (oldfd);
return newfd; return newfd;
} }
@ -274,12 +271,12 @@ main (int ignored_argc, char **ignored_argv)
else if (argv[ARG_STDIN][0] == 'z') else if (argv[ARG_STDIN][0] == 'z')
{ {
fd = open ("NUL:", O_RDONLY); fd = open ("NUL:", O_RDONLY);
checked_dup2 (fd, 0, child_err_report_fd, TRUE); checked_dup2 (fd, 0, child_err_report_fd);
} }
else else
{ {
fd = atoi (argv[ARG_STDIN]); fd = atoi (argv[ARG_STDIN]);
checked_dup2 (fd, 0, child_err_report_fd, TRUE); checked_dup2 (fd, 0, child_err_report_fd);
} }
if (argv[ARG_STDOUT][0] == '-') if (argv[ARG_STDOUT][0] == '-')
@ -287,12 +284,12 @@ main (int ignored_argc, char **ignored_argv)
else if (argv[ARG_STDOUT][0] == 'z') else if (argv[ARG_STDOUT][0] == 'z')
{ {
fd = open ("NUL:", O_WRONLY); fd = open ("NUL:", O_WRONLY);
checked_dup2 (fd, 1, child_err_report_fd, TRUE); checked_dup2 (fd, 1, child_err_report_fd);
} }
else else
{ {
fd = atoi (argv[ARG_STDOUT]); fd = atoi (argv[ARG_STDOUT]);
checked_dup2 (fd, 1, child_err_report_fd, TRUE); checked_dup2 (fd, 1, child_err_report_fd);
} }
saved_stderr_fd = reopen_noninherited (dup (2), _O_WRONLY); saved_stderr_fd = reopen_noninherited (dup (2), _O_WRONLY);
@ -305,12 +302,12 @@ main (int ignored_argc, char **ignored_argv)
else if (argv[ARG_STDERR][0] == 'z') else if (argv[ARG_STDERR][0] == 'z')
{ {
fd = open ("NUL:", O_WRONLY); fd = open ("NUL:", O_WRONLY);
checked_dup2 (fd, 2, child_err_report_fd, TRUE); checked_dup2 (fd, 2, child_err_report_fd);
} }
else else
{ {
fd = atoi (argv[ARG_STDERR]); fd = atoi (argv[ARG_STDERR]);
checked_dup2 (fd, 2, child_err_report_fd, TRUE); checked_dup2 (fd, 2, child_err_report_fd);
} }
/* argv[ARG_WORKING_DIRECTORY] is the directory in which to run the /* argv[ARG_WORKING_DIRECTORY] is the directory in which to run the
@ -354,11 +351,11 @@ main (int ignored_argc, char **ignored_argv)
} }
maxfd++; maxfd++;
child_err_report_fd = checked_dup2 (child_err_report_fd, maxfd, child_err_report_fd, TRUE); child_err_report_fd = checked_dup2 (child_err_report_fd, maxfd, child_err_report_fd);
maxfd++; maxfd++;
helper_sync_fd = checked_dup2 (helper_sync_fd, maxfd, child_err_report_fd, TRUE); helper_sync_fd = checked_dup2 (helper_sync_fd, maxfd, child_err_report_fd);
maxfd++; maxfd++;
saved_stderr_fd = checked_dup2 (saved_stderr_fd, maxfd, child_err_report_fd, TRUE); saved_stderr_fd = checked_dup2 (saved_stderr_fd, maxfd, child_err_report_fd);
{ {
GHashTableIter iter; GHashTableIter iter;
@ -373,13 +370,13 @@ main (int ignored_argc, char **ignored_argv)
* fds are larger than any target fd to avoid introducing new conflicts. * fds are larger than any target fd to avoid introducing new conflicts.
*/ */
maxfd++; maxfd++;
checked_dup2 (GPOINTER_TO_INT (sourcefd), maxfd, child_err_report_fd, TRUE); checked_dup2 (GPOINTER_TO_INT (sourcefd), maxfd, child_err_report_fd);
g_hash_table_iter_replace (&iter, GINT_TO_POINTER (maxfd)); g_hash_table_iter_replace (&iter, GINT_TO_POINTER (maxfd));
} }
g_hash_table_iter_init (&iter, fds); g_hash_table_iter_init (&iter, fds);
while (g_hash_table_iter_next (&iter, &targetfd, &sourcefd)) while (g_hash_table_iter_next (&iter, &targetfd, &sourcefd))
checked_dup2 (GPOINTER_TO_INT (sourcefd), GPOINTER_TO_INT (targetfd), child_err_report_fd, TRUE); checked_dup2 (GPOINTER_TO_INT (sourcefd), GPOINTER_TO_INT (targetfd), child_err_report_fd);
} }
g_hash_table_add (fds, GINT_TO_POINTER (child_err_report_fd)); g_hash_table_add (fds, GINT_TO_POINTER (child_err_report_fd));

View File

@ -856,8 +856,6 @@ g_spawn_async_with_pipes (const gchar *working_directory,
* windows on the right screen, you may want to use #GdkAppLaunchContext, * windows on the right screen, you may want to use #GdkAppLaunchContext,
* #GAppLaunchContext, or set the `DISPLAY` environment variable. * #GAppLaunchContext, or set the `DISPLAY` environment variable.
* *
* On Windows, sharing the same FD for @stdout_fd and @stderr_fd is not supported.
*
* Returns: %TRUE on success, %FALSE if an error was set * Returns: %TRUE on success, %FALSE if an error was set
* *
* Since: 2.68 * Since: 2.68
@ -940,8 +938,6 @@ g_spawn_async_with_pipes_and_fds (const gchar *working_directory,
* Identical to g_spawn_async_with_pipes_and_fds() but with `n_fds` set to zero, * Identical to g_spawn_async_with_pipes_and_fds() but with `n_fds` set to zero,
* so no FD assignments are used. * so no FD assignments are used.
* *
* On Windows, sharing the same FD for @stdout_fd and @stderr_fd is not supported.
*
* Returns: %TRUE on success, %FALSE if an error was set * Returns: %TRUE on success, %FALSE if an error was set
* *
* Since: 2.58 * Since: 2.58

View File

@ -196,9 +196,7 @@ test_spawn_async_with_fds (void)
{ NO_FD, NO_FD, NO_FD }, /* Test with no fds passed */ { NO_FD, NO_FD, NO_FD }, /* Test with no fds passed */
{ NO_FD, FD_NEGATIVE, NO_FD }, /* Test another negative fd value */ { NO_FD, FD_NEGATIVE, NO_FD }, /* Test another negative fd value */
{ PIPE, PIPE, PIPE }, /* Test with unique fds passed */ { PIPE, PIPE, PIPE }, /* Test with unique fds passed */
#ifndef G_OS_WIN32
{ NO_FD, PIPE, STDOUT_PIPE }, /* Test the same fd for stdout + stderr */ { NO_FD, PIPE, STDOUT_PIPE }, /* Test the same fd for stdout + stderr */
#endif
}; };
arg = g_strdup_printf ("thread %d", tnum); arg = g_strdup_printf ("thread %d", tnum);