Repository navigation
_interpchannels: missing PyErr_NoMemory() causes SystemErroron OOM in {create,close}() #150213
Description
Bug report
Bug description:
Bug description
parent issue:#146102
refs:https://gist.github.com/devdanzin/d9975354c27e57f2589acfd0a777a2f1
Several allocation failure paths in Modules/_interpchannelsmodule.c
return NULL or -1 without setting an exception.
This violates CPython's C API convention that an error return should have
an exception set. In release builds, this can surface as:
SystemError: <built-in function ...> returned NULL without setting an exception
instead of the expected MemoryError. In debug builds, the same paths may
trip assert(PyErr_Occurred()) in handle_channel_error().
Affected functions
The affected allocation sites are:
| Function | Triggered via |
|---|---|
_channelends_new() |
_channels.create() |
_channel_new() |
_channels.create() |
_channelref_new() |
_channels.create() |
_channel_set_closing() |
_channels.close(send=True) on a non-empty channel |
Nearby helper functions in the same file already handle this correctly by
calling PyErr_NoMemory() on allocation failure, for example:
| Function |
|---|
_channelitem_new() |
_channelqueue_new() |
_channelend_new() |
Reproducer
import _testcapi
import _interpchannels as _channels
from concurrent.interpreters import _crossinterp
REPLACE = _crossinterp._UNBOUND_CONSTANT_TO_FLAG[_crossinterp.UNBOUND]
# Case 1: _channels.create()
for n in range(1, 20):
_testcapi.set_nomemory(n, n + 1)
try:
cid = _channels.create(REPLACE)
except MemoryError:
pass
except SystemError as exc:
print(f"[create] n={n}: {type(exc).__name__}: {exc}")
else:
_channels.destroy(cid)
finally:
_testcapi.remove_mem_hooks()
# Case 2: _channels.close(send=True) on a non-empty channel
for n in range(1, 30):
cid = _channels.create(REPLACE)
_channels.send(cid, b"spam", blocking=False)
_testcapi.set_nomemory(n, n + 1)
try:
_channels.close(cid, send=True)
except MemoryError:
pass
except SystemError as exc:
print(f"[close] n={n}: {type(exc).__name__}: {exc}")
finally:
_testcapi.remove_mem_hooks()
try:
_channels.close(cid, force=True)
except Exception:
pass
try:
_channels.destroy(cid)
except Exception:
passSample output on main, CPython 3.16.0a0, macOS, release build:
[create] n=1: SystemError: <built-in function create> returned NULL without setting an exception
[create] n=3: SystemError: <built-in function create> returned NULL without setting an exception
[create] n=4: SystemError: <built-in function create> returned NULL without setting an exception
[close] n=1: SystemError: <built-in function close> returned NULL without setting an exception
Expected behavior
All affected allocation failure paths should raise MemoryError, consistent
with nearby helper functions and CPython's general C API error handling
contract.
Fix
Call PyErr_NoMemory() before returning an error from the affected
allocation failure paths.
CPython versions tested on:
CPython main branch
Operating systems tested on:
macOS
Linked PRs
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsDone
Activity
pythongh-150213: Fix OOM error handling in _interpchannels
[-]_interpchannels:missingPyErr_NoMemory()causesSystemErroronOOMincreate()/close()[/-][+]`_interpchannels`: missing `PyErr_NoMemory()` causes `SystemErroron` OOM in `{create,close}()`[/+]ZeroIntensity commentedon May 22, 2026
@ericsnowcurrently I'm wondering whether it's worth keeping
_interpchannelsaround at all. It seems to be a maintenance burden, quite out of date, and we don't use it anywhere right now.I think interpreter queues and the cross-interpreter protocol are sufficient for sharing things long-term. I'd be in favor of removing the module altogether and just sticking with those.
lpyu001 commentedon Jun 12, 2026
fix in #151239