PyO3 / PyO3/pyo3

[PyPy] Segfault in PyErr_Fetch when calling .hash()? inside __getitem__

Open
#6,109 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
16.2k
Forks
1k
Avg merge
2d 6h
Merged PRs (30d)
66

Description

Bug Description

Calling bound.hash()? inside a __getitem__ method causes a segmentation fault on PyPy 3.11, instead of propagating the error normally. This does not reproduce on CPython 3.10+.

Error in cpyext, CPython compatibility layer:
The function PyErr_Fetch was not supposed to fail
Fatal error in cpyext, CPython compatibility layer, calling PyErr_Fetch
Either report a bug or consider not using this particular extension
<SystemError object at 0x7f969a9cfa70>
RPython traceback:
  File "pypy_module_cpyext.c", line 14892, in wrapper_second_level__star_3_1
  File "pypy_module_cpyext_1.c", line 51447, in not_supposed_to_fail
zsh: segmentation fault (core dumped)  python3 a.py
Steps to Reproduce
  1. In Rust side:
fn __getitem__(
    &self,
    py: pyo3::Python,
    key: alias::PyObject,
) -> pyo3::PyResult<alias::PyObject> {
    let bound = key.bind(py);
    bound.hash()?; // <-- triggers the issue

    Err(new_py_error!(
        PyKeyError,
        Into::<alias::PyObject>::into(key)
    ))
}
  1. In Python side:
cache = MyClass()

def should_raise_recursive_error(key):
    try:
        cache[key]
    except KeyError:
        pass

    return should_raise_recursive_error(key)

should_raise_recursive_error("same-key")
Backtrace

Your operating system and version

Linux awolverp-82h8 7.0.10-1-MANJARO #1 SMP PREEMPT_DYNAMIC Sun, 24 May 2026 04:47:00 +0000 x86_64 GNU/Linux

Your Python version (python --version)

Python 3.11.15 (dc0121776214, Apr 28 2026, 06:57:54) [PyPy 7.3.22 with GCC 10.2.1 20210130 (Red Hat 10.2.1-11)]

Your Rust version (rustc --version)

rustc 1.98.0-nightly (57d06900f 2026-05-27)

Your PyO3 version

0.28.3

How did you install python? Did you use a virtualenv?

uv venv --python pypy-3.11.15-linux-x86_64-gnu

Additional Info

The recursion should eventually raise a standard RecursionError:

RecursionError: maximum recursion depth exceeded

But the actual behavior is PyPy crashes with a segmentation fault.

To narrow down the issue, I added println! debug statements inside PyErrStateNormalized::take (in PyO3's source), around the PyErr_Fetch call:

#[cfg(not(Py_3_12))]
{
    // ...
    println!("calling PyErr_Fetch");
    ffi::PyErr_Fetch(&mut ptype, &mut pvalue, &mut ptraceback);
    println!("PyErr_Fetch is OK");
     // ...
}

Output:

calling PyErr_Fetch
PyErr_Fetch is OK
calling PyErr_Fetch
Error in cpyext, CPython compatibility layer:
The function PyErr_Fetch was not supposed to fail
...
zsh: segmentation fault (core dumped)  python3 a.py

This shows that PyErr_Fetch succeeds on the first call but fails on the second call.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with PyErrStateNormalized::take and the PyErr_Fetch call shown in the report, then reproduce the Rust getitem example on PyPy 3.11. Compare the first and second PyErr_Fetch calls and verify that recursive access raises RecursionError instead of crashing. No specific source file or test is named, so trace the relevant PyO3 error-handling path before adding regression coverage.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, rust
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.