gspawn: Port to g_poll() from select()

This removes the limitation of select() that only FDs with values lower
than FD_SETSIZE can be used. Previously, if the out/err pipe FDs had
high values (which could happen if a large process, like Firefox, was
spawning subprocesses while having a lot of FDs open), GLib would abort
due to an assertion failure in libc.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

Fixes: #954
This commit is contained in:
Philip Withnall 2019-10-25 16:36:45 +01:00
parent 5e17a98d19
commit a7242d4a5e

View File

@ -372,7 +372,6 @@ g_spawn_sync (const gchar *working_directory,
gint outpipe = -1; gint outpipe = -1;
gint errpipe = -1; gint errpipe = -1;
GPid pid; GPid pid;
fd_set fds;
gint ret; gint ret;
GString *outstr = NULL; GString *outstr = NULL;
GString *errstr = NULL; GString *errstr = NULL;
@ -435,16 +434,16 @@ g_spawn_sync (const gchar *working_directory,
(outpipe >= 0 || (outpipe >= 0 ||
errpipe >= 0)) errpipe >= 0))
{ {
FD_ZERO (&fds); /* Any negative FD in the array is ignored, so we can use a fixed length.
if (outpipe >= 0) * We can use UNIX FDs here without worrying about Windows HANDLEs because
FD_SET (outpipe, &fds); * the Windows implementation is entirely in gspawn-win32.c. */
if (errpipe >= 0) GPollFD fds[] =
FD_SET (errpipe, &fds); {
{ outpipe, G_IO_IN | G_IO_HUP | G_IO_ERR, 0 },
ret = select (MAX (outpipe, errpipe) + 1, { errpipe, G_IO_IN | G_IO_HUP | G_IO_ERR, 0 },
&fds, };
NULL, NULL,
NULL /* no timeout */); ret = g_poll (fds, G_N_ELEMENTS (fds), -1 /* no timeout */);
if (ret < 0) if (ret < 0)
{ {
@ -458,13 +457,13 @@ g_spawn_sync (const gchar *working_directory,
g_set_error (error, g_set_error (error,
G_SPAWN_ERROR, G_SPAWN_ERROR,
G_SPAWN_ERROR_READ, G_SPAWN_ERROR_READ,
_("Unexpected error in select() reading data from a child process (%s)"), _("Unexpected error in reading data from a child process (%s)"),
g_strerror (errsv)); g_strerror (errsv));
break; break;
} }
if (outpipe >= 0 && FD_ISSET (outpipe, &fds)) if (outpipe >= 0 && fds[0].revents != 0)
{ {
switch (read_data (outstr, outpipe, error)) switch (read_data (outstr, outpipe, error))
{ {
@ -483,7 +482,7 @@ g_spawn_sync (const gchar *working_directory,
break; break;
} }
if (errpipe >= 0 && FD_ISSET (errpipe, &fds)) if (errpipe >= 0 && fds[1].revents != 0)
{ {
switch (read_data (errstr, errpipe, error)) switch (read_data (errstr, errpipe, error))
{ {