Skip to content

Commit 920c2b9

Browse files
committed
Detach socket on create_connection/create_unix_connection cancellation
When create_connection(sock=sock) or create_unix_connection(sock=sock) is cancelled or raises, tr._close() closes the fd via libuv but the Python socket object still believes it owns that fd number. Its __del__ later closes whatever fd the OS recycled into that slot, corrupting unrelated transports. Call sock.detach() on the error path so the Python socket sets its internal fd to -1, matching the semantics of standard asyncio where the transport always takes full ownership of the socket. Fixes #738
1 parent a308f75 commit 920c2b9

2 files changed

Lines changed: 28 additions & 0 deletions

File tree

tests/test_tcp.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,6 +1181,32 @@ def client():
11811181
# let it close
11821182
self.loop.run_until_complete(asyncio.sleep(0.1))
11831183

1184+
def test_create_connection_sock_cancel_detaches(self):
1185+
async def client(addr):
1186+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1187+
sock.setblocking(False)
1188+
try:
1189+
sock.connect(addr)
1190+
except BlockingIOError:
1191+
pass
1192+
await asyncio.sleep(0.01)
1193+
1194+
task = asyncio.ensure_future(
1195+
self.loop.create_connection(asyncio.Protocol, sock=sock))
1196+
await asyncio.sleep(0)
1197+
task.cancel()
1198+
with self.assertRaises(asyncio.CancelledError):
1199+
await task
1200+
1201+
# After cancellation the socket must be detached (fd == -1)
1202+
# so that its __del__ won't close a recycled fd.
1203+
self.assertEqual(sock.fileno(), -1)
1204+
1205+
with self.tcp_server(lambda sock: sock.recv_all(1),
1206+
max_clients=1,
1207+
backlog=1) as srv:
1208+
self.loop.run_until_complete(client(srv.addr))
1209+
11841210
@unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'no Unix sockets')
11851211
def test_create_connection_wrong_sock(self):
11861212
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

uvloop/loop.pyx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2065,6 +2065,7 @@ cdef class Loop:
20652065
# up in `Transport._call_connection_made()`, and calling
20662066
# `_close()` before it is fine.
20672067
tr._close()
2068+
sock.detach()
20682069
raise
20692070

20702071
tr._attach_fileobj(sock)
@@ -2307,6 +2308,7 @@ cdef class Loop:
23072308
raise
23082309
except BaseException:
23092310
tr._close()
2311+
sock.detach()
23102312
raise
23112313

23122314
tr._attach_fileobj(sock)

0 commit comments

Comments
 (0)