https://github.com/python/cpython/commit/1461f0475b55154c0c4e033caae83e29b75f3e4d
commit: 1461f0475b55154c0c4e033caae83e29b75f3e4d
branch: main
author: Seungki Kim <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-08-23T10:10:56Z
summary:

gh-155934: Fix socket leak and silent error for asyncio accepted connections 
(#155936)

files:
A Misc/NEWS.d/next/Library/2026-08-17-18-00-00.gh-issue-155934.acCept.rst
M Lib/asyncio/selector_events.py
M Lib/test/test_asyncio/test_selector_events.py

diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py
index 83916160b9fbde..16d5c1b6f0a3e1 100644
--- a/Lib/asyncio/selector_events.py
+++ b/Lib/asyncio/selector_events.py
@@ -253,7 +253,9 @@ async def _accept_connection2(
         except (SystemExit, KeyboardInterrupt):
             raise
         except BaseException as exc:
-            if self._debug:
+            if transport is None:
+                conn.close()
+            if transport is None or self._debug:
                 context = {
                     'message':
                         'Error on transport creation for incoming connection',
diff --git a/Lib/test/test_asyncio/test_selector_events.py 
b/Lib/test/test_asyncio/test_selector_events.py
index cf46c13fa5e1f3..a323084d262ebf 100644
--- a/Lib/test/test_asyncio/test_selector_events.py
+++ b/Lib/test/test_asyncio/test_selector_events.py
@@ -421,6 +421,60 @@ def 
test_accept_connection_reschedules_once_on_resource_error(self):
         self.assertEqual(self.loop.call_exception_handler.call_count, 1)
         self.assertEqual(self.loop.call_later.call_count, 1)
 
+    def test_accept_connection2_factory_error_closes_conn(self):
+        # gh-155934: if the transport was never created, the accepted
+        # socket is closed and the error is reported even when debug
+        # mode is disabled.
+        self.loop.set_debug(False)
+        conn = mock.Mock()
+
+        def factory():
+            raise RuntimeError("protocol_factory failed")
+
+        self.loop.call_exception_handler = mock.Mock()
+        self.loop.run_until_complete(
+            self.loop._accept_connection2(factory, conn, {}))
+
+        self.assertTrue(conn.close.called)
+        self.loop.call_exception_handler.assert_called_once()
+
+    def test_accept_connection2_transport_error_closes_conn(self):
+        # gh-155934: same when the transport creation itself fails.
+        self.loop.set_debug(False)
+        conn = mock.Mock()
+        self.loop._make_socket_transport = mock.Mock(
+            side_effect=ZeroDivisionError)
+        self.loop.call_exception_handler = mock.Mock()
+
+        self.loop.run_until_complete(
+            self.loop._accept_connection2(mock.Mock(), conn, {}))
+
+        self.assertTrue(conn.close.called)
+        self.loop.call_exception_handler.assert_called_once()
+
+    def test_accept_connection2_waiter_error_stays_debug_only(self):
+        # Once the transport exists it owns the socket: waiter failures
+        # (e.g. SSL handshake errors) close the transport and stay
+        # debug-only, and the accepted socket is not closed directly.
+        self.loop.set_debug(False)
+        conn = mock.Mock()
+        transport = mock.Mock()
+
+        def make_transport(conn, protocol, waiter=None, **kwargs):
+            waiter.set_exception(OSError("handshake failed"))
+            return transport
+
+        self.loop._make_socket_transport = make_transport
+        self.loop.call_exception_handler = mock.Mock()
+
+        self.loop.run_until_complete(
+            self.loop._accept_connection2(mock.Mock(), conn, {}))
+
+        self.assertTrue(transport.close.called)
+        self.assertFalse(conn.close.called)
+        self.assertFalse(self.loop.call_exception_handler.called)
+
+
 class SelectorTransportTests(test_utils.TestCase):
 
     def setUp(self):
diff --git 
a/Misc/NEWS.d/next/Library/2026-08-17-18-00-00.gh-issue-155934.acCept.rst 
b/Misc/NEWS.d/next/Library/2026-08-17-18-00-00.gh-issue-155934.acCept.rst
new file mode 100644
index 00000000000000..cc949bab5cb0bb
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-08-17-18-00-00.gh-issue-155934.acCept.rst
@@ -0,0 +1,3 @@
+Fix a socket leak in :mod:`asyncio` when transport creation fails for a
+connection accepted by a server, and report the error via the loop exception
+handler even when debug mode is disabled.

_______________________________________________
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]

Reply via email to