Skip to content

asyncio socket transport never closes after writelines() with an empty chunk #155888

Description

@deadlovelll

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

Metadata

Metadata

Assignees

No one assigned

    Labels

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

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions