gh-135836: Fix `IndexError` in `asyncio.create_connection()` (#135875) · python/cpython@9084b15 · GitHub | Latest TMZ Celebrity News & Gossip | Watch TMZ Live
Skip to content

Commit 9084b15

Browse files
gh-135836: Fix IndexError in asyncio.create_connection() (#135875)
1 parent 135ba86 commit 9084b15

File tree

3 files changed

+67
-30
lines changed

3 files changed

+67
-30
lines changed

Lib/asyncio/base_events.py

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,38 +1016,43 @@ async def _connect_sock(self, exceptions, addr_info, local_addr_infos=None):
10161016
family, type_, proto, _, address = addr_info
10171017
sock = None
10181018
try:
1019-
sock = socket.socket(family=family, type=type_, proto=proto)
1020-
sock.setblocking(False)
1021-
if local_addr_infos is not None:
1022-
for lfamily, _, _, _, laddr in local_addr_infos:
1023-
# skip local addresses of different family
1024-
if lfamily != family:
1025-
continue
1026-
try:
1027-
sock.bind(laddr)
1028-
break
1029-
except OSError as exc:
1030-
msg = (
1031-
f'error while attempting to bind on '
1032-
f'address {laddr!r}: {str(exc).lower()}'
1033-
)
1034-
exc = OSError(exc.errno, msg)
1035-
my_exceptions.append(exc)
1036-
else: # all bind attempts failed
1037-
if my_exceptions:
1038-
raise my_exceptions.pop()
1039-
else:
1040-
raise OSError(f"no matching local address with {family=} found")
1041-
await self.sock_connect(sock, address)
1042-
return sock
1043-
except OSError as exc:
1044-
my_exceptions.append(exc)
1045-
if sock is not None:
1046-
sock.close()
1047-
raise
1019+
try:
1020+
sock = socket.socket(family=family, type=type_, proto=proto)
1021+
sock.setblocking(False)
1022+
if local_addr_infos is not None:
1023+
for lfamily, _, _, _, laddr in local_addr_infos:
1024+
# skip local addresses of different family
1025+
if lfamily != family:
1026+
continue
1027+
try:
1028+
sock.bind(laddr)
1029+
break
1030+
except OSError as exc:
1031+
msg = (
1032+
f'error while attempting to bind on '
1033+
f'address {laddr!r}: {str(exc).lower()}'
1034+
)
1035+
exc = OSError(exc.errno, msg)
1036+
my_exceptions.append(exc)
1037+
else: # all bind attempts failed
1038+
if my_exceptions:
1039+
raise my_exceptions.pop()
1040+
else:
1041+
raise OSError(f"no matching local address with {family=} found")
1042+
await self.sock_connect(sock, address)
1043+
return sock
1044+
except OSError as exc:
1045+
my_exceptions.append(exc)
1046+
raise
10481047
except:
10491048
if sock is not None:
1050-
sock.close()
1049+
try:
1050+
sock.close()
1051+
except OSError:
1052+
# An error when closing a newly created socket is
1053+
# not important, but it can overwrite more important
1054+
# non-OSError error. So ignore it.
1055+
pass
10511056
raise
10521057
finally:
10531058
exceptions = my_exceptions = None

Lib/test/test_asyncio/test_base_events.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
MOCK_ANY = mock.ANY
2525

2626

27+
class CustomError(Exception):
28+
pass
29+
30+
2731
def tearDownModule():
2832
asyncio._set_event_loop_policy(None)
2933

@@ -1326,6 +1330,31 @@ def getaddrinfo_task(*args, **kwds):
13261330
self.assertEqual(len(cm.exception.exceptions), 1)
13271331
self.assertIsInstance(cm.exception.exceptions[0], OSError)
13281332

1333+
@patch_socket
1334+
def test_create_connection_connect_non_os_err_close_err(self, m_socket):
1335+
# Test the case when sock_connect() raises non-OSError exception
1336+
# and sock.close() raises OSError.
1337+
async def getaddrinfo(*args, **kw):
1338+
return [(2, 1, 6, '', ('107.6.106.82', 80))]
1339+
1340+
def getaddrinfo_task(*args, **kwds):
1341+
return self.loop.create_task(getaddrinfo(*args, **kwds))
1342+
1343+
self.loop.getaddrinfo = getaddrinfo_task
1344+
self.loop.sock_connect = mock.Mock()
1345+
self.loop.sock_connect.side_effect = CustomError
1346+
sock = mock.Mock()
1347+
m_socket.socket.return_value = sock
1348+
sock.close.side_effect = OSError
1349+
1350+
coro = self.loop.create_connection(MyProto, 'example.com', 80)
1351+
self.assertRaises(
1352+
CustomError, self.loop.run_until_complete, coro)
1353+
1354+
coro = self.loop.create_connection(MyProto, 'example.com', 80, all_errors=True)
1355+
self.assertRaises(
1356+
CustomError, self.loop.run_until_complete, coro)
1357+
13291358
def test_create_connection_multiple(self):
13301359
async def getaddrinfo(*args, **kw):
13311360
return [(2, 1, 6, '', ('0.0.0.1', 80)),
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix :exc:`IndexError` in :meth:`asyncio.loop.create_connection` that could
2+
occur when non-\ :exc:`OSError` exception is raised during connection and
3+
socket's ``close()`` raises :exc:`!OSError`.

0 commit comments

Comments
 (0)

TMZ Celebrity News – Breaking Stories, Videos & Gossip

Looking for the latest TMZ celebrity news? You've come to the right place. From shocking Hollywood scandals to exclusive videos, TMZ delivers it all in real time.

Whether it’s a red carpet slip-up, a viral paparazzi moment, or a legal drama involving your favorite stars, TMZ news is always first to break the story. Stay in the loop with daily updates, insider tips, and jaw-dropping photos.

🎥 Watch TMZ Live

TMZ Live brings you daily celebrity news and interviews straight from the TMZ newsroom. Don’t miss a beat—watch now and see what’s trending in Hollywood.