Skip to content

create_connection and create_server in asyncio didn't work with a Python build with IPv6 disabled #121913

Closed
@aisk

Description

@aisk

Bug report

Bug description:

Build Python with the configuration --disable-ipv6, and run the test with ./python.exe -m test test_asyncio.test_events -m 'test_create_connection_local_addr_skip_different_family' -v. You will encounter the following error stack:

ERROR: test_create_connection_local_addr_skip_different_family (test.test_asyncio.test_events.SelectEventLoopTests.test_create_connection_local_addr_skip_different_family)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/asaka/Codes/cpython/Lib/asyncio/base_events.py", line 1026, in _connect_sock
    sock.bind(laddr)
OSError: bind(): bad family

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/asaka/Codes/cpython/Lib/test/test_asyncio/test_events.py", line 695, in test_create_connection_local_addr_skip_different_family
    self.loop.run_until_complete(f)
  File "/Users/asaka/Codes/cpython/Lib/asyncio/base_events.py", line 721, in run_until_complete
    return future.result()
  File "/Users/asaka/Codes/cpython/Lib/asyncio/base_events.py", line 1138, in create_connection
    sock = await self._connect_sock(exceptions, addrinfo, laddr_infos)
  File "/Users/asaka/Codes/cpython/Lib/asyncio/base_events.py", line 1032, in _connect_sock
    f'{exc.strerror.lower()}'
AttributeError: 'NoneType' object has no attribute 'lower'

This issue not only affects the test but also user's code.

After some research, I found that it's caused by these two functions, which use getaddrinfo to get a list of connection infos and then attempt to call bind for each of the infos, ignoring OSError until a working one is found.

However, in the iteration code, it attempts to use OSError().strerror to create a new error. Unfortunately, some OSError instances have a strerror field of None. The error raised by sock.bind with AF_INET6 when --disable-ipv6 is used does not have this field, leading to an error that prevents the iteration loop from trying the next potential solution.

There are already reports for the missing strerror / errno fields issues: #109601 and #50720 with a draft PR #109720.

But before we fix this issue, should we provide a workaround for this specific problem, like using str(exc) instead of exc.strerror, or skip this loop if not socket.has_ipv6 and current family is AF_INET6?

CPython versions tested on:

CPython main branch

Operating systems tested on:

macOS

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibPython modules in the Lib dirtopic-asynciotype-bugAn unexpected behavior, bug, or error

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions