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:
pass
Sample 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
Bug report
Bug description:
Bug description
parent issue:#146102
refs:https://gist.github.com/devdanzin/d9975354c27e57f2589acfd0a777a2f1
Several allocation failure paths in
Modules/_interpchannelsmodule.creturn
NULLor-1without 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:
instead of the expected
MemoryError. In debug builds, the same paths maytrip
assert(PyErr_Occurred())inhandle_channel_error().Affected functions
The affected allocation sites are:
_channelends_new()_channels.create()_channel_new()_channels.create()_channelref_new()_channels.create()_channel_set_closing()_channels.close(send=True)on a non-empty channelNearby helper functions in the same file already handle this correctly by
calling
PyErr_NoMemory()on allocation failure, for example:_channelitem_new()_channelqueue_new()_channelend_new()Reproducer
Sample output on main, CPython 3.16.0a0, macOS, release build:
Expected behavior
All affected allocation failure paths should raise
MemoryError, consistentwith nearby helper functions and CPython's general C API error handling
contract.
Fix
Call
PyErr_NoMemory()before returning an error from the affectedallocation failure paths.
CPython versions tested on:
CPython main branch
Operating systems tested on:
macOS
Linked PRs