Skip to content

struct.Struct crashes (seg fault) under concurrent re-initialization and unpack in free-threading builds #146020

@sampsonc

Description

@sampsonc

Crash report

What happened?

Description

struct.Struct.__init__() can be called on an already-initialized Struct with a different format, which frees and replaces s_codes without any lock. Concurrent calls to unpack() or pack() read s_codes without any lock, producing a seg fault.

_struct.c declares Py_MOD_GIL_NOT_USED but has zero @critical_section annotations and no atomic operations on s_codes, s_size, or s_len.

Reproducer Code

import sys
import threading
import warnings

if sys._is_gil_enabled():
    sys.exit("SKIP: requires --disable-gil build")

s = struct.Struct('I')

def reader():
    for _ in range(5_000_000):
        try:
            s.unpack(b'\x00\x00\x00\x00')
        except Exception:
            pass

def reinit():
    with warnings.catch_warnings():
        warnings.simplefilter("ignore", FutureWarning)
        for _ in range(1_000_000):
            s.__init__('i')  # different format -> frees s_codes
            s.__init__('I')  # back again      -> frees s_codes again

readers = [threading.Thread(target=reader) for _ in range(4)]
writers = [threading.Thread(target=reinit) for _ in range(4)]
for t in writers + readers:
    t.start()
for t in writers + readers:
    t.join()

print("Completed without crash.")

Test Output
[1] 24871 segmentation fault ./python3 /tmp/test_struct_race.py

Note
Re-initialization of Struct is already deprecated (FutureWarning) and will be removed in a future version, which would close this race. However
I was able to trigger the crash today.

CPython versions tested on:

3.15

Operating systems tested on:

macOS

Output from running 'python -VV' on the command line:

Python 3.15.0a7+ free-threading build (heads/main:e167e06f8c6, Mar 15 2026, 09:14:39) [Clang 17.0.0 (clang-1700.6.4.2)]

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions