FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

gh-131064: Handle closed pipes consistently in communicate by limadog9 · Pull Request #159855 · python/cpython · GitHub

Repository navigation

gh-131064: Handle closed pipes consistently in communicate - #159855

Open
limadog9 wants to merge 1 commit into
python:mainfrom
limadog9:gh-131064-communicate-closed-pipes
Open

limadog9 wants to merge 1 commit into
python:mainfrom
limadog9:gh-131064-communicate-closed-pipes

Conversation

limadog9 commented Oct 20, 2026 •
edited
Loading

Copy link
Copy Markdown
Contributor

Make Popen.communicate() handle already-closed pipes consistently across its optimized path, selector path, and Windows reader threads. Closed output pipes return the same empty bytes or string that the selector path already returned. Sending nonempty input to closed stdin raises ValueError before communication starts; calls without input still succeed.

Add regressions covering stdout and stderr, one or multiple pipes, binary and text modes, and calls with and without timeouts. Check that communication can still finish after rejected input. Set the existing broken-pipe mocks' closed state explicitly so they continue to exercise open pipes.

Fixes #131064.

Validation:

  • The closed-output regression reproduces six failing cases on unmodified main. The stdin regression fails in all 16 subcases with the previous revision and passes with explicit validation.
  • Full subprocess suite on a free-threaded debug build: 375 tests, 48 skipped.
  • All 46 communicate tests also pass on a GIL debug build.
  • Seven tests exercise the Windows communication methods using real POSIX pipes. Native Windows validation is left to CI.
  • Ruff, NEWS lint, and patchcheck.

pekkaklarck left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

As the submitter of the original issue this looks pretty good to me. I only looked at this on a mobile screen, didn't check are all code paths covered and didn't properly check what the added test does, though.

Comment thread Lib/subprocess.py Outdated
Comment thread Lib/subprocess.py Outdated
Comment thread Lib/subprocess.py Outdated
limadog9 force-pushed the gh-131064-communicate-closed-pipes branch from f530e02 to c5bd418 Compare October 20, 2026 11:09

Copy link
Copy Markdown
Contributor Author

@pekkaklarck Thanks for the review. I’ve updated and squashed the changes:

  • Sending nonempty input to closed stdin now raises ValueError before communication starts. Calling without input still works, and the tests cover both cases.
  • Changed the stdout/stderr expressions to the ordering you suggested.
  • The reader thread now skips closed streams without appending anything. Joining the buffers afterward preserves empty bytes/strings for captured streams and None for uncaptured streams.

limadog9 force-pushed the gh-131064-communicate-closed-pipes branch from c5bd418 to 8970d4b Compare October 20, 2026 12:50
Comment thread Lib/subprocess.py Outdated
limadog9 force-pushed the gh-131064-communicate-closed-pipes branch from 8970d4b to be7ceb7 Compare October 20, 2026 15:32

Copy link
Copy Markdown
Contributor Author

@pekkaklarck Agreed, I’ve moved fh.close() inside the if not fh.closed block

Comment thread Lib/subprocess.py
stderr = stderr[0] if stderr else None
empty_output = '' if self.text_mode else b''
stdout = empty_output.join(stdout) if stdout is not None else None
stderr = empty_output.join(stderr) if stderr is not None else None

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

It seems to me that these changes aren't needed. At this point stdout and stderr are either None or lists self._stdout_buff or self._stderr_buff, respectively. These lists earlier contained exactly one value, but now they can also be empty. The existing if stdout/if stderr conditions cover both the None case and then empty list case.

I consider the current code rather confusing, though, and would consider changing it to something like this:

stdout = None
stderr = None
if self.stdout:
    self.stdout.close()
    if self._stdout_buff:
        stdout = self._stdout_buff[0]
if self.stderr:
    self.stderr.close()
    if self._stderr_buff:
        stderr = self._stderr_buff[0]

return (stdout, stderr)

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Inconsistent Popen.communicate() behavior if stdin/stdout/stderr is closed PIPE

2 participants


Back | FazBrowse Home | New Git URL