Skip to content

Commit 4a741af

Browse files
committed
Close the resource only when protocol_factory() fails
On the proactor, _make_*_transport() takes ownership of the socket/pipe and starts I/O before it can raise, so closing it in connect_*()/create_*() double-manages it (broke test_windows_events). Close only when protocol_factory() raises, before any transport exists.
1 parent c643223 commit 4a741af

2 files changed

Lines changed: 12 additions & 12 deletions

File tree

Lib/asyncio/base_events.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,13 +1499,13 @@ async def create_datagram_endpoint(self, protocol_factory,
14991499

15001500
try:
15011501
protocol = protocol_factory()
1502-
waiter = self.create_future()
1503-
transport = self._make_datagram_transport(
1504-
sock, protocol, r_addr, waiter)
15051502
except:
1506-
# gh-156400: close the socket if the transport is never created.
1503+
# gh-156400: no transport owns the socket yet, so close it.
15071504
sock.close()
15081505
raise
1506+
waiter = self.create_future()
1507+
transport = self._make_datagram_transport(
1508+
sock, protocol, r_addr, waiter)
15091509
if self._debug:
15101510
if local_addr:
15111511
logger.info("Datagram endpoint local_addr=%r remote_addr=%r "
@@ -1721,12 +1721,12 @@ async def connect_accepted_socket(
17211721
async def connect_read_pipe(self, protocol_factory, pipe):
17221722
try:
17231723
protocol = protocol_factory()
1724-
waiter = self.create_future()
1725-
transport = self._make_read_pipe_transport(pipe, protocol, waiter)
17261724
except:
1727-
# gh-156400: close the pipe if the transport is never created.
1725+
# gh-156400: no transport owns the pipe yet, so close it.
17281726
pipe.close()
17291727
raise
1728+
waiter = self.create_future()
1729+
transport = self._make_read_pipe_transport(pipe, protocol, waiter)
17301730

17311731
try:
17321732
await waiter
@@ -1742,12 +1742,12 @@ async def connect_read_pipe(self, protocol_factory, pipe):
17421742
async def connect_write_pipe(self, protocol_factory, pipe):
17431743
try:
17441744
protocol = protocol_factory()
1745-
waiter = self.create_future()
1746-
transport = self._make_write_pipe_transport(pipe, protocol, waiter)
17471745
except:
1748-
# gh-156400: close the pipe if the transport is never created.
1746+
# gh-156400: no transport owns the pipe yet, so close it.
17491747
pipe.close()
17501748
raise
1749+
waiter = self.create_future()
1750+
transport = self._make_write_pipe_transport(pipe, protocol, waiter)
17511751

17521752
try:
17531753
await waiter

Misc/NEWS.d/next/Library/2026-08-26-13-58-01.gh-issue-156400.dGrmP1.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
Fix socket and pipe leaks in :mod:`asyncio` when ``protocol_factory()`` or
2-
transport creation fails in :meth:`loop.create_datagram_endpoint
1+
Fix socket and pipe leaks in :mod:`asyncio` when ``protocol_factory()`` raises
2+
in :meth:`loop.create_datagram_endpoint
33
<asyncio.loop.create_datagram_endpoint>`, :meth:`loop.connect_read_pipe
44
<asyncio.loop.connect_read_pipe>`, and :meth:`loop.connect_write_pipe
55
<asyncio.loop.connect_write_pipe>`. The socket or pipe is now closed instead

0 commit comments

Comments
 (0)