[PyPy] Segfault in PyErr_Fetch when calling .hash()? inside __getitem__
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
- 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)
))
}
- 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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