Skip to content

Crash with PyGILState_Ensure called from background thread during finalization on Python 3.14.0a7 #132948

@davidhewitt

Description

@davidhewitt

Crash report

What happened?

Coming over from work on PyO3's branch to support Python 3.14.

We have a crash which can be narrowed down to calling PyGilState_Ensure in a background thread while finalization is underway. This seems to be new in 3.14.

// src/lib.rs
use pyo3_ffi::*;

static mut MODULE_DEF: PyModuleDef = PyModuleDef {
    m_base: PyModuleDef_HEAD_INIT,
    m_name: c"pyo3_scratch".as_ptr(),
    m_doc: c"Demonstration of PyGILState_Ensure crash.".as_ptr(),
    m_size: 0,
    m_methods: unsafe { METHODS as *const [PyMethodDef] as *mut PyMethodDef },
    m_slots: unsafe { SLOTS as *const [PyModuleDef_Slot] as *mut PyModuleDef_Slot },
    m_traverse: None,
    m_clear: None,
    m_free: None,
};

static mut SLOTS: &[PyModuleDef_Slot] = &[
    PyModuleDef_Slot {
        slot: Py_mod_gil,
        value: Py_MOD_GIL_NOT_USED,
    },
    unsafe { std::mem::zeroed() },
];

static mut METHODS: &[PyMethodDef] = &[
    // A zeroed PyMethodDef to mark the end of the array.
    PyMethodDef::zeroed(),
];

// The module initialization function, which must be named `PyInit_<your_module>`.
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn PyInit_pyo3_scratch() -> *mut PyObject {
    std::thread::spawn(|| {
        loop {
            // Repeatedly acquire and release the GIL;
            unsafe {
                PyGILState_Release(PyGILState_Ensure());
            }
        }
    });
    PyModuleDef_Init(std::ptr::addr_of_mut!(MODULE_DEF))
}
# Cargo.toml
[package]
name = "pyo3-scratch"
version = "0.1.0"
edition = "2021"

[lib]
name = "pyo3_scratch"
crate-type = ["cdylib"]

[dependencies]
pyo3-ffi = { version = "0.24" }
# pyproject.toml
[build-system]
requires = ["maturin>=1,<2"]
build-backend = "maturin"

[project]
dynamic = ["version"]
name = "pyo3-scratch"
requires-python = ">=3.6"

[tool.maturin]
features = ["pyo3-ffi/extension-module"]

Reproduce by

  • install the module
  • python -c "import pyo3_scratch"
  • observe segfault (not every time)

lldb backtrace:

(lldb) t 2
* thread #2, stop reason = EXC_BAD_ACCESS (code=1, address=0x1d09)
    frame #0: 0x0000000100898664 libpython3.14.dylib`_PyThreadState_Attach [inlined] bind_gilstate_tstate(tstate=0x00000001600041c0) at pystate.c:331:48 [opt]
   328      // XXX assert(!tstate->_status.active);
   329      assert(!tstate->_status.bound_gilstate);
   330 
-> 331      _PyRuntimeState *runtime = tstate->interp->runtime;
   332      PyThreadState *tcur = gilstate_tss_get(runtime);
   333      assert(tstate != tcur);
   334 
(lldb) bt
* thread #2, stop reason = EXC_BAD_ACCESS (code=1, address=0x1d09)
  * frame #0: 0x0000000100898664 libpython3.14.dylib`_PyThreadState_Attach [inlined] bind_gilstate_tstate(tstate=0x00000001600041c0) at pystate.c:331:48 [opt]
    frame #1: 0x0000000100898660 libpython3.14.dylib`_PyThreadState_Attach [inlined] tstate_activate(tstate=0x00000001600041c0) at pystate.c:2055:9 [opt]
    frame #2: 0x0000000100898658 libpython3.14.dylib`_PyThreadState_Attach(tstate=0x00000001600041c0) at pystate.c:2145:9 [opt]
    frame #3: 0x00000001008699ec libpython3.14.dylib`PyEval_RestoreThread(tstate=<unavailable>) at ceval_gil.c:654:5 [opt] [artificial]
    frame #4: 0x000000010089912c libpython3.14.dylib`PyGILState_Ensure at pystate.c:2840:9 [opt]
    frame #5: 0x00000001003a15d4 pyo3_scratch.cpython-314-darwin.so`std::sys::backtrace::__rust_begin_short_backtrace::h0e87d186cf26a828 + 12
    frame #6: 0x00000001003a0d44 pyo3_scratch.cpython-314-darwin.so`core::ops::function::FnOnce::call_once$u7b$$u7b$vtable.shim$u7d$$u7d$::h10c677eeb05c5f18 + 108
    frame #7: 0x00000001003c1710 pyo3_scratch.cpython-314-darwin.so`std::sys::pal::unix::thread::Thread::new::thread_start::h6d53b1b0c047a3b9 + 52
    frame #8: 0x000000018d9c9c0c libsystem_pthread.dylib`_pthread_start + 136

CPython versions tested on:

3.14

Operating systems tested on:

macOS

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

Python 3.14.0a7 (main, Apr 25 2025, 15:33:43) [Clang 17.0.0 (clang-1700.0.13.3)]

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.14bugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)type-crashA hard crash of the interpreter, possibly with a core dump

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions