diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 2044d2a42897e9..28edfc1de5b079 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -1921,12 +1921,13 @@ def _execute_child(self, args, executable, preexec_fn, close_fds, # Wait for exec to fail or succeed; possibly raising an # exception (limited in size) - errpipe_data = bytearray() - while True: - part = os.read(errpipe_read, 50000) - errpipe_data += part - if not part or len(errpipe_data) > 50000: - break + errpipe_data = bytearray(50000) + unread = memoryview(errpipe_data) + while count := os.readinto(errpipe_read, unread): + unread = unread[count:] + bytes_left = len(unread) + del unread + del errpipe_data[-bytes_left:] finally: # be sure the FD is closed no matter what os.close(errpipe_read) diff --git a/Misc/NEWS.d/next/Library/2025-02-02-20-55-18.gh-issue-129205.hb1iMy.rst b/Misc/NEWS.d/next/Library/2025-02-02-20-55-18.gh-issue-129205.hb1iMy.rst new file mode 100644 index 00000000000000..70e028a7c7fa38 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-02-02-20-55-18.gh-issue-129205.hb1iMy.rst @@ -0,0 +1 @@ +:mod:`subprocess` forkserver now uses a fixed 50,000 byte buffer to read startup errors from the child processes it runs. Previously there could be up to 100,000 bytes read with multiple allocations and copies.