Skip to content

FreeTypeFont is not thread-safe with free threading #9497

Description

@colesbury

This was originally discovered by a colleague. Using a FreeTypeFont created by ImageFont.truetype(...) from multiple threads crashes.

This looks like a limitation of the freetype library:

https://github.com/freetype/freetype/blob/07d8d50a63a45a7446b2fc44732baecc685f3e4c/docs/CHANGES#L1634-L1635

I think we can use a critical section to lock around operations on a FontObject / FT_Face.

What actually happened?

Segmentation fault

What are your OS, Python and Pillow versions?

  • OS: linux
  • Python: 3.14t
  • Pillow: 12.2.0.dev0
Pillow version:
     Pillow 12.2.0.dev0
     Python 3.14.3+ free-threading build (heads/3.14:fa3143a1d2d, Mar 25 2026, 14:10:06) [Clang 20.1.8 (++20250804090239+87f0227cb601-1~exp1~20250804210352.139)]
     --------------------------------------------------------------------
     Python executable is /home/sgross/cpython/python
     System Python files loaded from /usr/local
     --------------------------------------------------------------------
     Python Pillow modules loaded from /home/sgross/pillow/src/PIL
     Binary Pillow modules loaded from /home/sgross/pillow/src/PIL
     --------------------------------------------------------------------
     --- PIL CORE support ok, compiled for 12.2.0.dev0
     --- TKINTER support ok, loaded 8.6
     --- FREETYPE2 support ok, loaded 2.13.2
     *** LITTLECMS2 support not installed
     *** WEBP support not installed
     *** AVIF support not installed
     --- JPEG support ok, compiled for libjpeg-turbo 2.1.5
     *** OPENJPEG (JPEG2000) support not installed
     --- ZLIB (PNG/ZIP) support ok, loaded 1.3
     *** LIBTIFF support not installed
     *** RAQM (Bidirectional Text) support not installed
     *** LIBIMAGEQUANT (Quantization method) support not installed
     --- XCB (X protocol) support ok
     --------------------------------------------------------------------
import sys
import threading

from PIL import ImageFont

for i in range(10):
    font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", size=24)
    barrier = threading.Barrier(4)

    def worker():
        barrier.wait()
        for _ in range(1000):
            font.getmetrics()
            font.getlength("Hello, world!")


    threads = [threading.Thread(target=worker) for _ in range(4)]
    for t in threads:
        t.start()
    for t in threads:
        t.join()
print("ok")

Activity

  1. colesbury commented on Mar 25, 2026

    @colesbury
    ContributorAuthor

    I'll put up a PR for review soon. I think the fix is pretty straightforward.

  2. added a commit that references this issue on Mar 25, 2026
    a912615
  3. added a commit that references this issue on Mar 26, 2026
    e4d72b5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions