gsubprocesslauncher: Don’t close target FDs in close() method

This is a regression introduced in commit 67a589e505. Previously, the
source/target FD pairs were stored in `needdup_fd_assignments`, in
consecutive entries, so source FDs had even indices and target FDs had
odd indices.

I didn’t notice that the array index was being incremented by 2 when
closing FDs, when porting from the old code. So previously the code was
only closing the source FDs; after the port, it was closing source and
target FDs.

That’s incorrect, as the target FDs are just integers in the parent
process. It’s only in the child process where they are actually FDs —
and `g_subprocess_launcher_close()` is never called in the child
process.

This resulted in some strange misbehaviours in any process which used
`g_subprocess_launcher_take_fd()` with target FDs which could have
possibly aliased with other FDs in the parent process (and which weren’t
equal to their mapped source FDs).

Thanks to Olivier Fourdan for the detailed bug report.

Signed-off-by: Philip Withnall <pwithnall@endlessos.org>

Fixes: #2332
This commit is contained in:
Philip Withnall 2021-02-19 18:20:25 +00:00
parent 1e74c52a63
commit 55a75590d0
2 changed files with 6 additions and 6 deletions

View File

@ -42,8 +42,8 @@ struct _GSubprocessLauncher
gint stderr_fd;
gchar *stderr_path;
GArray *source_fds;
GArray *target_fds; /* always the same length as source_fds */
GArray *source_fds; /* GSubprocessLauncher has ownership of the FD elements */
GArray *target_fds; /* always the same length as source_fds; elements are just integers and not FDs in this process */
gboolean closed_fd;
GSpawnChildSetupFunc child_setup_func;

View File

@ -661,11 +661,11 @@ g_subprocess_launcher_close (GSubprocessLauncher *self)
g_assert (self->target_fds != NULL);
g_assert (self->source_fds->len == self->target_fds->len);
/* Note: Dont close the target_fds, as theyre only valid FDs in the
* child process. This code never executes in the child process. */
for (i = 0; i < self->source_fds->len; i++)
{
(void) close (g_array_index (self->source_fds, int, i));
(void) close (g_array_index (self->target_fds, int, i));
}
(void) close (g_array_index (self->source_fds, int, i));
g_clear_pointer (&self->source_fds, g_array_unref);
g_clear_pointer (&self->target_fds, g_array_unref);
}