-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
bpo-32270: Don't close stdin/out/err in pass_fds #6242
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Modules/_posixsubprocess.c
Outdated
| /* Close pipe fds. Make sure we don't close the same fd more than */ | ||
| /* once, or standard fds. */ | ||
| if (p2cread > 2) | ||
| if (p2cread > 2 && !_is_fd_in_sorted_fd_sequence(p2cread, py_fds_to_keep)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that there is no need to manually close p2cread at all, and other two descriptors need to be closed only if they are the result of dup above. This is because if a descriptor is created by subprocess.py (a pipe or for /dev/null), it's non-inheritable, and if a descriptor is specified by the user, is not in pass_fds and is > 2, it will be closed by _close_open_fds. So my original idea of fixing this issue was to add an async-signal-safe version of _Py_dup and use it instead of dup above, and then just remove these three checks.
Note also that p2cwrite and its three friends are never required to be manually closed since they are always non-inheritable pipe ends created by subprocess.py.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not surprising. The original code here predates our non-inheritable file descriptor implementation. I'm examining this vs your izbyshev@b89b52f changes to see what makes the most sense.
This change as is does make it pass your unittest.
When subprocess.Popen() stdin= stdout= or stderr= handles are specified and appear in pass_fds=, don't close the original fds after dup'ing them.
b883088 to
657fd10
Compare
Taken from izbyshev@b89b52f per the suggestion in the BPO issue comment.
Based on code review by izbyshev@ and izbyshev@b89b52f. This also removes the old manual p2cread, c2pwrite, and errwrite closing logic as inheritable flags and _close_open_fds takes care of them properly today. This code is within child_exec() where it is the only thread so there is no race condition between the dup and _Py_set_inheritable_async_safe call.
|
With the latest changes, this PR is essentially @izbyshev's code from their own branch. :) Thanks for the eyeballs and review! |
|
Thanks @gpshead for the PR 🌮🎉.. I'm working now to backport this PR to: 3.6, 3.7. |
When subprocess.Popen() stdin= stdout= or stderr= handles are specified and appear in pass_fds=, don't close the original fds after dup'ing them. This implementation and unittest primarily came from @izbyshev (see the PR) See also izbyshev@b89b52f This also removes the old manual p2cread, c2pwrite, and errwrite closing logic as inheritable flags and _close_open_fds takes care of that properly today without special treatment. This code is within child_exec() where it is the only thread so there is no race condition between the dup and _Py_set_inheritable_async_safe call. (cherry picked from commit ce34410) Co-authored-by: Gregory P. Smith <[email protected]>
|
GH-9148 is a backport of this pull request to the 3.7 branch. |
|
GH-9149 is a backport of this pull request to the 3.6 branch. |
When subprocess.Popen() stdin= stdout= or stderr= handles are specified and appear in pass_fds=, don't close the original fds after dup'ing them. This implementation and unittest primarily came from @izbyshev (see the PR) See also izbyshev@b89b52f This also removes the old manual p2cread, c2pwrite, and errwrite closing logic as inheritable flags and _close_open_fds takes care of that properly today without special treatment. This code is within child_exec() where it is the only thread so there is no race condition between the dup and _Py_set_inheritable_async_safe call. (cherry picked from commit ce34410) Co-authored-by: Gregory P. Smith <[email protected]>
When subprocess.Popen() stdin= stdout= or stderr= handles are specified and appear in pass_fds=, don't close the original fds after dup'ing them. This implementation and unittest primarily came from @izbyshev (see the PR) See also izbyshev@b89b52f This also removes the old manual p2cread, c2pwrite, and errwrite closing logic as inheritable flags and _close_open_fds takes care of that properly today without special treatment. This code is within child_exec() where it is the only thread so there is no race condition between the dup and _Py_set_inheritable_async_safe call. (cherry picked from commit ce34410) Co-authored-by: Gregory P. Smith <[email protected]> [Google]
When subprocess.Popen() stdin= stdout= or stderr= handles are specified and appear in pass_fds=, don't close the original fds after dup'ing them. This implementation and unittest primarily came from @izbyshev (see the PR) See also izbyshev@b89b52f This also removes the old manual p2cread, c2pwrite, and errwrite closing logic as inheritable flags and _close_open_fds takes care of that properly today without special treatment. This code is within child_exec() where it is the only thread so there is no race condition between the dup and _Py_set_inheritable_async_safe call. (cherry picked from commit ce34410) Co-authored-by: Gregory P. Smith <[email protected]> [Google]
When subprocess.Popen() stdin= stdout= or stderr= handles are specified and
appear in pass_fds=, don't close their original fds after dup2'ing them to 0/1/2.
I still need to create a proper unittest and NEWS entry before this can be merged.
https://bugs.python.org/issue32270