Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
davidhewitt opened this issue Apr 25, 2025 · 3 comments
Labels
3.14 bugs and security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs) type-crash A hard crash of the interpreter, possibly with a core dump

Comments

@davidhewitt
Copy link
Contributor

davidhewitt commented Apr 25, 2025

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)]

@davidhewitt davidhewitt added the type-crash A hard crash of the interpreter, possibly with a core dump label Apr 25, 2025
@picnixz picnixz added interpreter-core (Objects, Python, Grammar, and Parser dirs) 3.14 bugs and security fixes labels Apr 25, 2025
@picnixz
Copy link
Member

picnixz commented Apr 25, 2025

Any hope to bisect the commit? @ZeroIntensity you work quite a lot with PyGIL* and co so maybe you have an idea?

@ZeroIntensity
Copy link
Member

This is a known issue (gh-124619). I'm in the midst of fixing it for 3.14.

@picnixz picnixz closed this as completed Apr 25, 2025
@davidhewitt
Copy link
Contributor Author

Fantastic, thank you. 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.14 bugs and security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs) type-crash A hard crash of the interpreter, possibly with a core dump
Projects
None yet
Development

No branches or pull requests

3 participants