https://github.com/python/cpython/commit/b090d06e7331c40b3c94e70b35a09f785b279e17
commit: b090d06e7331c40b3c94e70b35a09f785b279e17
branch: main
author: Timofei <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-07-16T11:35:25+05:30
summary:
gh-153761: Fix asyncio sock_accept() dropping a connection when cancelled
(#153762)
files:
A Misc/NEWS.d/next/Library/2026-07-15-14-24-18.gh-issue-153761.8jqs67.rst
M Lib/asyncio/selector_events.py
M Lib/test/test_asyncio/test_sock_lowlevel.py
diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py
index 97cb6b76ac2e89..19ffd8cc98b0e9 100644
--- a/Lib/asyncio/selector_events.py
+++ b/Lib/asyncio/selector_events.py
@@ -714,6 +714,9 @@ async def sock_accept(self, sock):
return await fut
def _sock_accept(self, fut, sock):
+ # gh-153761: _sock_accept must not scheduled with already cancelled
future
+ if fut.done():
+ return
fd = sock.fileno()
try:
conn, address = sock.accept()
diff --git a/Lib/test/test_asyncio/test_sock_lowlevel.py
b/Lib/test/test_asyncio/test_sock_lowlevel.py
index 5d825440e41ca7..c68211968a80d8 100644
--- a/Lib/test/test_asyncio/test_sock_lowlevel.py
+++ b/Lib/test/test_asyncio/test_sock_lowlevel.py
@@ -1,5 +1,6 @@
import socket
import asyncio
+import select
import sys
import unittest
@@ -257,6 +258,38 @@ async def _basetest_sock_connect_racing(self, listener,
sock):
self.skipTest(skip_reason)
+ async def _basetest_sock_accept_racing(self, listener, sock):
+ # gh-153761: cancelling sock_accept() must not let a scheduled
+ # _sock_accept run on the cancelled future.
+ listener.setblocking(False)
+ listener.bind(('127.0.0.1', 0))
+ listener.listen(1)
+ addr = listener.getsockname()
+
+ errors = []
+ self.loop.set_exception_handler(lambda loop, ctx: errors.append(ctx))
+ task = asyncio.create_task(self.loop.sock_accept(listener))
+ await asyncio.sleep(0)
+
+ sock.connect(addr)
+ select.select([listener], [], [], support.SHORT_TIMEOUT)
+
+ self.loop.call_soon(task.cancel)
+ await asyncio.sleep(0)
+ await asyncio.sleep(0)
+
+ with self.assertRaises(asyncio.CancelledError):
+ await task
+ self.assertEqual(errors, [])
+
+ # The pending connection must survive
+ conn, conn_addr = await self.loop.sock_accept(listener)
+ with conn:
+ self.assertEqual(conn_addr, sock.getsockname())
+ sock.setblocking(False)
+ await self.loop.sock_sendall(conn, b'ping')
+ self.assertEqual(await self.loop.sock_recv(sock, 4), b'ping')
+
def test_sock_client_racing(self):
with test_utils.run_test_server() as httpd:
sock = socket.socket()
@@ -280,6 +313,16 @@ def test_sock_client_connect_racing(self):
self.loop.run_until_complete(asyncio.wait_for(
self._basetest_sock_connect_racing(listener, sock), 10))
+ def test_sock_accept_racing(self):
+ if sys.platform == 'win32':
+ if isinstance(self.loop, asyncio.ProactorEventLoop):
+ raise unittest.SkipTest('Not relevant to ProactorEventLoop')
+ listener = socket.socket()
+ sock = socket.socket()
+ with listener, sock:
+ self.loop.run_until_complete(asyncio.wait_for(
+ self._basetest_sock_accept_racing(listener, sock), 10))
+
async def _basetest_huge_content(self, address):
sock = socket.socket()
sock.setblocking(False)
diff --git
a/Misc/NEWS.d/next/Library/2026-07-15-14-24-18.gh-issue-153761.8jqs67.rst
b/Misc/NEWS.d/next/Library/2026-07-15-14-24-18.gh-issue-153761.8jqs67.rst
new file mode 100644
index 00000000000000..68e007e66e0396
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-07-15-14-24-18.gh-issue-153761.8jqs67.rst
@@ -0,0 +1 @@
+Fix cancelling :meth:`asyncio.loop.sock_accept` dropping a pending connection.
_______________________________________________
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]