Skip to content

array module declares Py_MOD_GIL_NOT_USED, but crashes (SIGSEGV) under concurrent access in free-threading builds #146007

@sampsonc

Description

@sampsonc

Crash report

What happened?

The array module sets {Py_mod_gil, Py_MOD_GIL_NOT_USED} in its module
slots, claiming free-threading support. None of its methods hold any
lock when accessing the internal buffer pointer ob_item. Concurrent
arr.clear() + arr[i] reliably produces a seg fault.

Build the latest cpython with --disable-gil.

Reproducer Code

import array
import sys
import threading

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

NUM_THREADS = 4
ITERS = 5_000_000
arr = array.array('i', list(range(10)))

def reader():
    for _ in range(ITERS):
        try:
            _ = arr[0]
        except IndexError:
            pass

def writer():
    for _ in range(ITERS):
        arr.clear()
        arr.extend(range(10))

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

print("COMPLETE:  without crash — race may not have triggered this run.")
print("Re-run on a multi-core machine, or increase NUM_THREADS / ITERS")

When running it, I observed:

Exception in thread Thread-5 (writer):
Exception in thread Thread-7 (writer):
Exception in thread Thread-6 (writer):
Traceback (most recent call last):
File "/Users/chs/builds/bin/lib/python3.15t/threading.py", line 1075, in _bootstrap_inner
self._context.run(self.run)
File "/Users/chs/builds/bin/lib/python3.15t/threading.py", line 1017, in run
self._target(*self._args, **self._kwargs)
File "/Users/chs/PycharmProjects/Scratch/toctou1.py", line 22, in writer
arr.extend(range(10))
IndexError: array assignment index out of range
Traceback (most recent call last):
Traceback (most recent call last):
[1] 51460 segmentation fault ./python3 /Users/chs/PycharmProjects/Scratch/toctou1.py

Root Cause:

Modules/arraymodule.c has no @critical_section annotations and no atomic operations on ob_item. array_resize(0) frees and nulls ob_item without any lock, while array_item reads ob_size and then dereferences ob_item without any lock. The same problem likely affects other methods.

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