Skip to content

Fix spawn dup ordering - #9578

Merged
headius merged 2 commits into
jruby:jruby-10.0from
headius:fix_spawn_dup_ordering
Aug 9, 2026
Merged

headius merged 2 commits into
jruby:jruby-10.0from
headius:fix_spawn_dup_ordering

Conversation

@headius

@headius headius commented Aug 9, 2026

Copy link
Copy Markdown
Member

The ordering here was leftover from ported CRuby logic and incorrectly did the redirects in reverse order. For in: STDOUT, this caused any redirect to the child's STDOUT to get used for the input of the in: redirect. Because that child STDOUT would be a pipe if not otherwise specified, the in: ended up with a non-TTY and broke our stty-based io-console logic (ruby/io-console#145).

Fixes #9577.

headius added 2 commits August 9, 2026 15:38
The logic here, ported from CRuby, had two different orders in
which it could perform the dups. If the parent's state had already
been saved, as for forking, the dups should proceed in ascending
order of the child descriptors. If the parent's state had not
already been saved, as for a non-forking spawn, the dups should
proceed in ascending order of the parent descriptors, lest they
get overwritten by subsequent dups.

The logic in CRuby is very messy, due to splicing both forking and
non-forking logic together in the same methods, and the JRuby port
went astray here. We captured the parent state, but because we do
not fork we did not actually handle that state as thought we were
in a forked child. We did, however, proceed to use the order of the
child descriptors to indicate the order of the dups, which resulted
in `in: STDOUT` seeing and duping the wrong stdout (i.e. whatever
stream would eventually be the child's stdout). In the example
cases from jruby#9577, this could be the popen pipe (not a
terminal), /dev/null (also not a terminal), or whatever was passed
to popen via `out:` redirect. In the working case there, that
redirect is `out: STDOUT`, accidentally making the correct parent
stdout available in the child for the `in:` dup.

The fix is to always use the ordering of the input descriptors,
since posix_spawn will perform the redirects for us in that order,
and we don't want lower descriptors to be overwritten before we
have a change to deal with them.

Fixes jruby#9577
An issue in JRuby's redirect-ordering logic for popen caused it to
overwrite STDOUT before redirecting it, resulting in STDIN getting
the wrong source descriptor. As a result, a child `stty` process
did not get the controlling terminal.

This spec tests that the redirect of STDOUT to STDIN happens before
any alteration of the child's STDOUT.

See jruby#9577 for details.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant