Skip to content

ProactorEventLoop datagram transports drop buffered datagrams on close() and never call connection_lost() #156920

Description

@graingert

Bug report

Bug description:

Closing a datagram transport that still has datagrams queued drops them and
never calls connection_lost(), so the socket is closed only by __del__,
with a ResourceWarning; SelectorEventLoop flushes them and tears down
normally. _ProactorDatagramTransport._loop_writing() returns at
if self._conn_lost: return, which close() has just incremented, so the
teardown branch below it -- the one close() deliberately leaves to the
write loop when the buffer is non-empty -- is unreachable.

Reproducer

import asyncio
import sys


async def main():
    loop = asyncio.get_running_loop()
    print(sys.version)
    print(type(loop).__name__)
    received = []
    lost = loop.create_future()

    class Receiver(asyncio.DatagramProtocol):
        def datagram_received(self, data, addr):
            received.append(data)

    class Sender(asyncio.DatagramProtocol):
        def connection_lost(self, exc):
            if not lost.done():
                lost.set_result(exc)

    recv_transport, _ = await loop.create_datagram_endpoint(
        Receiver, local_addr=('127.0.0.1', 0))
    addr = recv_transport.get_extra_info('sockname')

    transport, _ = await loop.create_datagram_endpoint(
        Sender, remote_addr=addr)

    for i in range(5):
        transport.sendto(b'datagram-%d' % i)
    transport.close()

    try:
        await asyncio.wait_for(lost, 5)
    except TimeoutError:
        print('connection_lost(): never called')
    else:
        print('connection_lost(): called')

    await asyncio.sleep(0.5)
    print('datagrams received:', len(received))
    print('write buffer size: ', transport.get_write_buffer_size())
    recv_transport.close()
    await asyncio.sleep(0)


asyncio.run(main(), loop_factory=asyncio.SelectorEventLoop)
asyncio.run(main(), loop_factory=asyncio.ProactorEventLoop)

Output on Windows:

PS C:\Users\tagra\projects\cpython> py -3.14 .\reproducer.py
3.14.7 (tags/v3.14.7:823f032, Aug  5 2026, 10:51:32) [MSC v.1944 64 bit (AMD64)]
_WindowsSelectorEventLoop
connection_lost(): called
datagrams received: 5
write buffer size:  0
3.14.7 (tags/v3.14.7:823f032, Aug  5 2026, 10:51:32) [MSC v.1944 64 bit (AMD64)]
ProactorEventLoop
connection_lost(): never called
datagrams received: 1
write buffer size:  72
PS C:\Users\tagra\projects\cpython> py -3.13 .\reproducer.py
3.13.15 (tags/v3.13.15:4061bc4, Aug  5 2026, 13:05:39) [MSC v.1944 64 bit (AMD64)]
_WindowsSelectorEventLoop
connection_lost(): called
datagrams received: 5
write buffer size:  0
3.13.15 (tags/v3.13.15:4061bc4, Aug  5 2026, 13:05:39) [MSC v.1944 64 bit (AMD64)]
ProactorEventLoop
connection_lost(): never called
datagrams received: 1
write buffer size:  72

CPython versions tested on

Py3.13 Py3.14

Operating systems tested on

Windows

CPython versions tested on:

3.13, 3.14

Operating systems tested on:

Windows

Linked PRs

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    OS-windowsstdlibStandard Library Python modules in the Lib/ directorytopic-asynciotype-bugAn unexpected behavior, bug, or error

    Projects

    • Status
      Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions