Skip to content

[Bug]: FT2Font.load_char() segfaults (null-pointer dereference) #32224

Description

@nevercodecorrect

Bug summary

FT2Font.load_char() segfaults (null-pointer dereference) on a font that FreeType accepts but for which the glyph lookup fails without setting a FreeType error code. The process dies; no Python except can catch it.

Code for reproduction

## Self-contained input (base64)

AQYFAFUAAAABAQFwHgDu7vXu7hJwDAJlLR4DAQEeACkBAR4Jbu7O7u7u7u7u7u7u7u7u7u7upWti
ZAAAgAAAAAAAAAAAVRIA7u4tGwEfAFUAHAAebu7u7u7u7u7u7u7u7hwRERH1Dx4AAQEBgR4A1///
//////0AKSj9AAAAAG0=



import base64, io, pathlib
pathlib.Path("missing-glyph-128.bin").write_bytes(base64.b64decode(B64))



import io, warnings
from matplotlib import ft2font

warnings.filterwarnings("ignore")
data = open("missing-glyph-128.bin", "rb").read()   # 128 bytes, attached

font = ft2font.FT2Font(io.BytesIO(data))            # succeeds
font.set_size(12.0, 72.0)
font.get_charmap()
try:
    font.get_sfnt()                                 # ValueError: No SFNT name table
except ValueError:
    pass
font.load_char(0x41)                                # <-- SIGSEGV

Actual outcome

UserWarning: Glyph 65 (A) missing from font(s) unknown family name.
Segmentation fault (core dumped)

Under ASAN:

AddressSanitizer: SEGV on unknown address 0xfffffffffffffff8
    #0 PyFT2Font_load_char(PyFT2Font*, long, LoadFlags)
    #1 pybind11::cpp_function::call_impl<PyGlyph*, ..., PyFT2Font*, long, LoadFlags>(...)
    #2 pybind11::cpp_function::dispatcher(_object*, _object* const*, unsigned long, _object*)

0xfffffffffffffff8 is nullptr - 8: std::vector::back() on an empty vector of 8-byte elements.

Expected outcome

A Python exception, or a .notdef glyph. A font that FreeType accepts but that has no usable glyph for a character should not be able to terminate the interpreter.

Additional information

Reproduced on the current release from PyPI wheels, same CPython 3.14.4:

matplotlib bundled FreeType result
3.10.9 2.6.1 survives
3.11.0 2.14.3 segfault
3.11.1 2.14.3 segfault

3.10.9 genuinely executes load_char and survives

Operating system

Ubuntu

Matplotlib Version

3.11.1

Matplotlib Backend

No response

Python version

3.14.4

Jupyter version

No response

Installation

pip

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions