BUG: Fix segfault in seterr() on self-referencing object array (gh-32… - #32620
Merged
Merged
Conversation
…gh-32609) Passing a self-referencing object array as the `all` (or `divide`/ `over`/`under`/`invalid`) argument to `numpy.seterr()` caused a segmentation fault instead of raising an exception. `errmodeconverter` in extobj.c compared the argument against candidate mode strings using `PyObject_RichCompareBool`. For a self-referencing object array this recurses into elementwise comparison machinery forever, since at every level the array (or a container reachable from it) is being compared against a string, never against itself, so no identity short-circuit applies. On platforms with larger per-frame C stack usage this exhausts the stack before Python's own recursion tracking can intervene, producing a segfault rather than a RecursionError. Fix this at its root by rejecting non-string, non-None values for these arguments before any comparison happens at all. Also add a Py_EnterRecursiveCall guard to array_richcompare's tp_richcompare slot as defense-in-depth for other callers that reach elementwise object-array comparison with self-referencing data, mirroring the existing guard for bool(array) self-containment (numpygh-8306, numpygh-9077). This alone is not sufficient to fix the seterr crash (confirmed by testing: the C-recursion counter guard doesn't reliably trip before the physical stack is exhausted, since numpy's ufunc dispatch path uses larger-than-typical per-frame stack usage), but is a reasonable additional safeguard. Closes numpygh-32609
ngoldbaum
reviewed
Sep 14, 2026
ngoldbaum
reviewed
Sep 14, 2026
Co-authored-by: Nathan Goldbaum <nathan.goldbaum@gmail.com>
Co-authored-by: Nathan Goldbaum <nathan.goldbaum@gmail.com>
ngoldbaum
reviewed
Sep 14, 2026
ngoldbaum
approved these changes
Sep 14, 2026
ngoldbaum
left a comment
Member
There was a problem hiding this comment.
Thanks! Try to keep diffs on PRs as minimal as possible, like this ended up 😄
Contributor
Author
Thanks to make my first contribution as memorial, will learn a lot from this and try to help team with more valuable fixes. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR summary
[Say how you found this — e.g. "I was fuzzing my numpy fork with fusil
when this came up."]
numpy.seterr()segfaults when passed a self-referencing object arrayinstead of raising an error. The cause is in
errmodeconverter(extobj.c), which compares the argument against candidate mode strings
using
PyObject_RichCompareBool. For a self-referencing object array thisrecurses forever into elementwise comparison, since at every level the
array is being compared against a plain string, not against itself, so
the identity short-circuit never kicks in.
The fix rejects non-string, non-None values before any comparison
happens, instead of trying to bound the recursion.
I also added a
Py_EnterRecursiveCallguard toarray_richcompare'stp_richcompareslot as defense-in-depth, matching the pattern from#8306/#9077. [Mention here if you want: testing showed this guard alone
doesn't fix the crash, since numpy's ufunc dispatch path uses larger
per-frame stack usage than the recursion counter assumes — the
extobj.c type check is what actually fixes it.]
Added two tests in test_errstate.py. Confirmed the existing
test_errstate.py suite (8/8) and the comparison-related tests in
test_multiarray.py (13/13) still pass.
First time contributor introduction
New to numpy. I've contributed to CPython before (PR triager) and built a
few developer tooling projects (docs translation coordination, review
toolkits for CPython/PyPy). Found this bug while fuzzing numpy with fusil.
AI Disclosure
No AI used.