You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
NumPy test failure after upgrading to 3.14.1t on MacOS x86_64 #142253
We can just skip this test in numpy. It's testing observed behavior in Python rather than anything that's being relied on in NumPy. See numpy/numpy@bb76bff for context on why the test was added.
@ngoldbaum do you want to re-open this? I dunno it's worth digging into, but this is now failing on NumPy main even on non x86 MacOS. And it seems very unlikely to be a NumPy issue as such.
Hi all, I think I understand what's happening now.
CPython is working as intended after the 3.14.1 stack-limit changes: with a genuinely large stack, deep C recursion now correctly completes instead of raising at an arbitrary depth. That invalidated NumPy's "must raise RecursionError at depth N" tests.
The segfaults were a NumPy bug that the same change exposed: arraydescr_dealloc recurses through nested subarray dtypes, so any deep dtype that construction is now allowed to finish became a possible C stack overflow. I have a fix for this that replaces the Py_DECREF(base) (which may trigger a deep C recursion) with a check that detaches the subarray chain to avoid recursion.
However, I think there are maybe some issues with the stack overflow detection in CPython. If a C extension like NumPy indicates via the C API that it's about to do some recursive operations, I think that violates assumptions in CPython's stack overflow protection code. If (for some reason) the recorded bounds overstate the real stack, recursion crashes with no diagnostics. See the reproducer below: claim 64 MiB on the (real 16 MiB / 8 MiB) main thread via ctypes, run nested json.loads — SIGSEGV on both 3.14.6 and 3.14.6t, with a recursion check passing at every single level.
stack_wrongbounds.py — overstated bounds ⇒ SIGSEGV despite a check at every level
importctypes, jsonlibc=ctypes.CDLL(None)
libc.pthread_self.restype=ctypes.c_void_plibc.pthread_get_stackaddr_np.restype=ctypes.c_void_plibc.pthread_get_stackaddr_np.argtypes= [ctypes.c_void_p]
api=ctypes.pythonapiapi.PyThreadState_Get.restype=ctypes.c_void_papi.PyUnstable_ThreadState_SetStackProtection.restype=ctypes.c_intapi.PyUnstable_ThreadState_SetStackProtection.argtypes= [
ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t]
top=libc.pthread_get_stackaddr_np(libc.pthread_self())
CLAIMED=64*2**20# real main-thread stack is 8-16 MiBassertapi.PyUnstable_ThreadState_SetStackProtection(
api.PyThreadState_Get(), top-CLAIMED, CLAIMED) ==0print("bounds set: claiming 64 MiB", flush=True)
try:
json.loads("["*1_000_000+"]"*1_000_000)
print("completed", flush=True)
exceptRecursionErrorase:
print("RecursionError:", e, flush=True)
# observed: neither line prints -- SIGSEGV (exit 139) on 3.14.6 and 3.14.6t
I think the issue is that Numpy dtype object is not a GC type so the trashcan mechanism and stack overflow protection doesn't kicks in. The object must be GC type so that CPython can delay the deallocation and avoid C stack overflow.
Activity
ngoldbaum commentedon Dec 4, 2025
Happy to help if there are NumPy internals questions that come up.
ngoldbaum commentedon Dec 4, 2025
Doesn't trigger on ARM Macs. Unfortunately that means I can't reproduce it or help bisect it on hardware I can easily use :(
colesbury commentedon Dec 4, 2025
This doesn't look free threading related. It looks like you don't have a 3.14 job in your matrix, just 3.14t.
Is this a bug in Python. It doesn't raise a RecursionError, but it doesn't crash. What's the problem? Does it crash if you raise the iterations?
The recursion check changed between 3.14.0 and 3.14.1:
cpython/Include/internal/pycore_ceval.h
Lines 199 to 203 in ebf955d
cpython/Include/internal/pycore_ceval.h
Lines 201 to 212 in 57e0d17
ngoldbaum commentedon Dec 4, 2025
We can just skip this test in numpy. It's testing observed behavior in Python rather than anything that's being relied on in NumPy. See numpy/numpy@bb76bff for context on why the test was added.
ngoldbaum commentedon Dec 4, 2025
I opened numpy/numpy#30375. IMO you can close this issue.
jorenham commentedon Dec 4, 2025
Alright, then let's.
Thanks for investigating @colesbury, @ngoldbaum!
seberg commentedon Jun 24, 2026
@ngoldbaum do you want to re-open this? I dunno it's worth digging into, but this is now failing on NumPy main even on non x86 MacOS. And it seems very unlikely to be a NumPy issue as such.
See also numpy/numpy#31733 and numpy/numpy#31364 (comment)
ngoldbaum commentedon Jul 3, 2026
Sorry, I've been meaning to spend some time finding the root cause of this. Let's go ahead and re-open the issue.
encukou commentedon Jul 28, 2026
Do you need help with the investigation?
ngoldbaum commentedon Jul 28, 2026
Hi all, I think I understand what's happening now.
arraydescr_deallocrecurses through nested subarray dtypes, so any deep dtype that construction is now allowed to finish became a possible C stack overflow. I have a fix for this that replaces thePy_DECREF(base)(which may trigger a deep C recursion) with a check that detaches the subarray chain to avoid recursion.However, I think there are maybe some issues with the stack overflow detection in CPython. If a C extension like NumPy indicates via the C API that it's about to do some recursive operations, I think that violates assumptions in CPython's stack overflow protection code. If (for some reason) the recorded bounds overstate the real stack, recursion crashes with no diagnostics. See the reproducer below: claim 64 MiB on the (real 16 MiB / 8 MiB) main thread via ctypes, run nested
json.loads— SIGSEGV on both 3.14.6 and 3.14.6t, with a recursion check passing at every single level.stack_wrongbounds.py — overstated bounds ⇒ SIGSEGV despite a check at every level
kumaraditya303 commentedon Jul 29, 2026
I think the issue is that Numpy dtype object is not a GC type so the trashcan mechanism and stack overflow protection doesn't kicks in. The object must be GC type so that CPython can delay the deallocation and avoid C stack overflow.
kumaraditya303 commentedon Jul 31, 2026
Closing as this is fixed in numpy.