All four modules declare Py_MOD_GIL_NOT_USED via PyUnstable_Module_SetGIL, claiming free-threading safety. However, the global slow_module pointer in bottleneck.h:143 has a lazy-init race condition (two threads could both see NULL and both import), and the 15 global interned pystr_* variables across all modules lack atomic access patterns.
Additionally, the modules use single-phase init (m_size = -1) with global state, which prevents subinterpreter isolation.
File(s): bottleneck.h:143-183 (slow_module race), all 4 template files (pystr_* globals, single-phase init)
See #518 for the complete report.
Found using cext-review-toolkit.
All four modules declare
Py_MOD_GIL_NOT_USEDviaPyUnstable_Module_SetGIL, claiming free-threading safety. However, the globalslow_modulepointer inbottleneck.h:143has a lazy-init race condition (two threads could both see NULL and both import), and the 15 global internedpystr_*variables across all modules lack atomic access patterns.Additionally, the modules use single-phase init (
m_size = -1) with global state, which prevents subinterpreter isolation.File(s):
bottleneck.h:143-183(slow_module race), all 4 template files (pystr_* globals, single-phase init)See #518 for the complete report.
Found using cext-review-toolkit.