gh-135836: Fix IndexError in asyncio.create_connection() (#135875)

This commit is contained in:
Serhiy Storchaka 2025-07-03 07:08:39 +03:00 committed by GitHub
parent 135ba86212
commit 9084b15156
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 67 additions and 30 deletions

View file

@ -1015,6 +1015,7 @@ class BaseEventLoop(events.AbstractEventLoop):
exceptions.append(my_exceptions)
family, type_, proto, _, address = addr_info
sock = None
try:
try:
sock = socket.socket(family=family, type=type_, proto=proto)
sock.setblocking(False)
@ -1042,12 +1043,16 @@ class BaseEventLoop(events.AbstractEventLoop):
return sock
except OSError as exc:
my_exceptions.append(exc)
if sock is not None:
sock.close()
raise
except:
if sock is not None:
try:
sock.close()
except OSError:
# An error when closing a newly created socket is
# not important, but it can overwrite more important
# non-OSError error. So ignore it.
pass
raise
finally:
exceptions = my_exceptions = None

View file

@ -24,6 +24,10 @@ import warnings
MOCK_ANY = mock.ANY
class CustomError(Exception):
pass
def tearDownModule():
asyncio._set_event_loop_policy(None)
@ -1326,6 +1330,31 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase):
self.assertEqual(len(cm.exception.exceptions), 1)
self.assertIsInstance(cm.exception.exceptions[0], OSError)
@patch_socket
def test_create_connection_connect_non_os_err_close_err(self, m_socket):
# Test the case when sock_connect() raises non-OSError exception
# and sock.close() raises OSError.
async def getaddrinfo(*args, **kw):
return [(2, 1, 6, '', ('107.6.106.82', 80))]
def getaddrinfo_task(*args, **kwds):
return self.loop.create_task(getaddrinfo(*args, **kwds))
self.loop.getaddrinfo = getaddrinfo_task
self.loop.sock_connect = mock.Mock()
self.loop.sock_connect.side_effect = CustomError
sock = mock.Mock()
m_socket.socket.return_value = sock
sock.close.side_effect = OSError
coro = self.loop.create_connection(MyProto, 'example.com', 80)
self.assertRaises(
CustomError, self.loop.run_until_complete, coro)
coro = self.loop.create_connection(MyProto, 'example.com', 80, all_errors=True)
self.assertRaises(
CustomError, self.loop.run_until_complete, coro)
def test_create_connection_multiple(self):
async def getaddrinfo(*args, **kw):
return [(2, 1, 6, '', ('0.0.0.1', 80)),

View file

@ -0,0 +1,3 @@
Fix :exc:`IndexError` in :meth:`asyncio.loop.create_connection` that could
occur when non-\ :exc:`OSError` exception is raised during connection and
socket's ``close()`` raises :exc:`!OSError`.