https://github.com/python/cpython/commit/fc53775ef5c35f3c926e258cef4adf82b913a649 commit: fc53775ef5c35f3c926e258cef4adf82b913a649 branch: 3.15 author: Miss Islington (bot) <[email protected]> committer: hugovk <[email protected]> date: 2026-09-28T19:00:52+03:00 summary:
[3.15] gh-89544: Fix IDLE hang after Restart Shell while receiving output (GH-157644) (#157970) Co-authored-by: Serhiy Storchaka <[email protected]> files: A Misc/NEWS.d/next/IDLE/2026-09-17-01-00-00.gh-issue-89544.rstbuf.rst M Lib/idlelib/idle_test/test_rpc.py M Lib/idlelib/rpc.py diff --git a/Lib/idlelib/idle_test/test_rpc.py b/Lib/idlelib/idle_test/test_rpc.py index 81eff398c72f45..15c3ed14b8f6f3 100644 --- a/Lib/idlelib/idle_test/test_rpc.py +++ b/Lib/idlelib/idle_test/test_rpc.py @@ -1,9 +1,28 @@ "Test rpc, coverage 20%." from idlelib import rpc +import socket +import struct import unittest +class SocketIOTest(unittest.TestCase): + + def test_reconnect_discards_partial_packet(self): + # gh-89544: RPCClient.accept() reinitializes the SocketIO after + # a restart; a partially received packet must not be kept. + old_sock, old_peer = socket.socketpair() + new_sock, new_peer = socket.socketpair() + with old_sock, old_peer, new_sock, new_peer: + sockio = rpc.SocketIO(old_sock) + old_peer.sendall(struct.pack('<i', 100) + b'x' * 10) + self.assertIsNone(sockio.pollpacket(1)) + sockio.close() + rpc.SocketIO.__init__(sockio, new_sock) + new_peer.sendall(struct.pack('<i', 3) + b'abc') + self.assertEqual(sockio.pollpacket(1), b'abc') + + class CodePicklerTest(unittest.TestCase): diff --git a/Lib/idlelib/rpc.py b/Lib/idlelib/rpc.py index 3f0b2230dd185d..9af9863d74e0b6 100644 --- a/Lib/idlelib/rpc.py +++ b/Lib/idlelib/rpc.py @@ -139,6 +139,11 @@ def __init__(self, sock, objtable=None, debugging=None): self.objtable = objtable self.responses = {} self.cvars = {} + # Receive buffer state. A new connection must not inherit a + # partially received packet from the old one (gh-89544). + self.buff = b'' + self.bufneed = 4 + self.bufstate = 0 # meaning: 0 => reading count; 1 => reading data def close(self): sock = self.sock @@ -345,10 +350,6 @@ def putmessage(self, message): raise OSError("socket no longer exists") s = s[n:] - buff = b'' - bufneed = 4 - bufstate = 0 # meaning: 0 => reading count; 1 => reading data - def pollpacket(self, wait): self._stage0() if len(self.buff) < self.bufneed: diff --git a/Misc/NEWS.d/next/IDLE/2026-09-17-01-00-00.gh-issue-89544.rstbuf.rst b/Misc/NEWS.d/next/IDLE/2026-09-17-01-00-00.gh-issue-89544.rstbuf.rst new file mode 100644 index 00000000000000..4a4c885eff9681 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2026-09-17-01-00-00.gh-issue-89544.rstbuf.rst @@ -0,0 +1,2 @@ +Fix IDLE hanging after Restart Shell while receiving a large output from the +user process. _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
