deadlovelll · GitHub

Bug report

Bug description:

An empty chunk passed to writelines() can never be drained, so the transport never finishes closing.

The current code will never return without raising TimeoutError:

import asyncio
import socket
async def main():
    s1, s2 = socket.socketpair()
    reader, writer = await asyncio.open_connection(sock=s1)
    writer.writelines([b'hello', b''])
    writer.close()
    try:
        await asyncio.wait_for(writer.wait_closed(), 3)
        print("closed")
    except TimeoutError:
        print("hang:", list(writer.transport._buffer))
asyncio.run(main())

But should finish with:

closed

Proposed fix - skip empty data chunks in writelines():

        for data in list_of_data:
            if not data:
                continue
            self._buffer.append(memoryview(data))
            self._buffer_size += len(data)
        if not self._buffer:
            return
        self._write_ready()

I have a fix ready

CPython versions tested on:

CPython main branch

Operating systems tested on:

macOS

Linked PRs

Read the original on github.com ↗