Skip to content

fix: raise SystemError when a key's C slot fails without an exception - #120

Merged
awolverp merged 2 commits into
awolverp:mainfrom
greenclaw:fix/pyerr-fetch
Oct 29, 2026
Merged

awolverp merged 2 commits into
awolverp:mainfrom
greenclaw:fix/pyerr-fetch

Conversation

@greenclaw

Copy link
Copy Markdown
Contributor

utils::pyobject_hash and utils::pyobject_equal assume an exception is set when PyObject_Hash returns -1 or PyObject_RichCompareBool returns a negative value: PyErr::take(py).unwrap() and PyErr::take(py).unwrap_unchecked(). A C type that reports an error without setting one breaks that assumption. It is a bug in that type, but with 6.2.9 it takes down the whole interpreter: the release profile has panic = "abort", so unwrap() aborts (exit code 134), and unwrap_unchecked() on None is undefined behaviour (in practice PyO3 aborts with "PyErr state should never be invalid outside of normalization"). A dict given the same key raises SystemError: ... returned NULL without setting an exception and goes on.

This adds a small take_error(py) that returns the pending exception or, if there is none, SystemError("error return without exception set"), and uses it at both call sites. I didn't use PyErr::fetch: in PyO3 0.30 it panics in debug builds and returns SystemError only in release, so the result would depend on the build profile and the test below could not tell the fixed code from the old one in CI.

Test

test_c_key_error_without_exception (in tests/test_hashing.py, for every cache class) builds such a type with ctypes + PyType_FromSpec — once with a tp_hash returning -1, once with a tp_richcompare returning NULL — in a child process, since the old code aborts, and expects SystemError. Skipped on PyPy (no ctypes.pythonapi).

  • Fork CI with the test alone on main (run): 14 failures on every CPython job (3.10–3.15, 3.14t, 3.15t, ubuntu, macos, windows), everything else passes.
  • With the fix (run): all jobs green.
  • Locally, a release build of this branch raises SystemError for both cases where PyPI 6.2.9 aborts.

@awolverp
awolverp merged commit 08d525d into awolverp:main Oct 29, 2026
11 of 12 checks passed
@greenclaw
greenclaw deleted the fix/pyerr-fetch branch October 29, 2026 11:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants