Skip to content

iconv codecs recurse without bound when the replacement is unencodable #155006

Description

@serhiy-storchaka

Bug report

A str returned by an error handler is re-encoded by a recursive _PyUnicode_EncodeIconv() call with the same errors, so a replacement that is itself unencodable calls the handler again, and again.

>>> codecs.register_error('bad', lambda e: ('€', e.end))
>>> 'a😀b'.encode('ascii', 'bad')
UnicodeEncodeError: 'ascii' codec can't encode character '\U0001f600' in position 1: ordinal not in range(128)
>>> codecs.iconv_encode('ASCII', 'a😀b', 'bad')
RecursionError: Stack overflow (used 8120 kB)

The standard handlers are enough for a charset that lacks the characters they emit, which is 274 of the encodings glibc provides here: the ISO-646 national variants and the EBCDIC family.

>>> 'a😀b'.encode('iso646-de', 'backslashreplace')   # 0x5c is Ö, no backslash
RecursionError: Stack overflow (used 8120 kB) while calling a Python object
>>> 'a😀b'.encode('iso646-fr', 'xmlcharrefreplace')  # 0x23 is £, no '#'
RecursionError: Stack overflow (used 8120 kB) while calling a Python object

The code page codec and the charmap codec encode the replacement once and raise if it does not fit. Re-encoding with strict would do the same here, and still write the correct byte for '?' in EBCDIC.

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.16new features, bugs and security fixesstdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    Status
    In Progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions