GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing github.com — create_connection(sock=sock) does not detach socket on cancellation, causing fd double-close · Issue #738 · MagicStack/uvloop Closed DescriptionSummaryWhen Standard asyncio is not affected — its transport directly owns the Python socket and properly closes it on the error path, setting Root causeIn # uvloop/loop.pyx ~line 2060 waiter = self._new_future() tr = TCPTransport.new(self, protocol, None, waiter, context) try: tr._open(sock.fileno()) # libuv takes over the fd tr._init_protocol() # _transports[fd] = tr await waiter # ← cancellation point except BaseException: tr._close() # libuv closes fd, but sock doesn't know raise tr._attach_fileobj(sock) # only reached on success — calls sock.detach() later via _close() On the success path, On the error/cancellation path, Reproductionimport asyncio import socket import uvloop async def test(loop): srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) srv.bind(("127.0.0.1", 0)) srv.listen(1) addr = srv.getsockname() client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.setblocking(False) try: client.connect(addr) except BlockingIOError: pass await asyncio.sleep(0.01) task = asyncio.ensure_future(loop.create_connection(asyncio.Protocol, sock=client)) await asyncio.sleep(0) task.cancel() try: await task except asyncio.CancelledError: pass print(f"uvloop: sock.fileno() = {client.fileno()}") # NOT -1 → bug srv.close() try: client.close() except OSError: pass # uvloop — socket NOT detached uvloop.install() loop = asyncio.new_event_loop() loop.run_until_complete(test(loop)) loop.close() # standard asyncio — socket properly detached asyncio.set_event_loop_policy(None) loop = asyncio.new_event_loop() loop.run_until_complete(test(loop)) loop.close() Output: ImpactUnder high concurrency with followed by Suggested fixDetach the socket in the error path: except BaseException: tr._close() if sock is not None: sock.detach() raise This matches the semantics of standard asyncio, where the transport always takes full ownership of the socket. Environment
Reacted by Matthew Lapointe and Huaiyi Zhao Activity
MetadataMetadataAssigneesLabelsNo labels TypeProjectsMilestoneRelationshipsDevelopmentIssue actions |
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |