Summary
Would you consider publishing greenlet 3.4.1 with the PyGreenlet_GetCurrent() error-setting fix that is already present in 3.5.0?
I realize #508 intentionally became 3.5.0 because removing the atexit callback changed shutdown behavior. I am not asking to backport that broader behavior change. The requested 3.4.1 change is only this line from 004e1e9:
static PyGreenlet*
PyGreenlet_GetCurrent(void)
{
if (greenlet::IsShuttingDown()) {
+ PyErr_SetString(PyExc_RuntimeError, "greenlet is being finalized");
return nullptr;
}
We have observed crashes in services using greenlet 3.4.0. Upgrading to the 3.5 line resolves the issue, but the fix itself appears small enough to backport to the 3.4 line without bringing in the broader shutdown behavior changes from 3.5. A 3.4.1 patch release could therefore provide a narrowly scoped fix for users who have not yet upgraded.
Reproducer
Environment:
- CPython 3.14.6
- gevent 26.4.0
- greenlet 3.4.0
- reproduced on x86_64; the original production family also occurs on aarch64
from gevent import monkey
monkey.patch_all()
from gevent.local import local
class X:
def __init__(self):
self.local = local()
self.local.value = 42
def __del__(self):
self.local.value
x = X()
For example:
$ uv venv --python 3.14.6 .venv
$ uv pip install --python .venv/bin/python gevent==26.4.0 greenlet==3.4.0
$ .venv/bin/python repro.py
Segmentation fault (core dumped)
$ echo $?
139
This reproduces 5/5 times here. No tracing or instrumentation library is imported.
The native stack ends in:
PyException_GetTraceback
PyTraceBack_Here
__Pyx_AddTraceback
__pyx_f_6gevent_14_gevent_clocal__local_get_dict
__pyx_tp_getattro_6gevent_14_gevent_clocal_local
PyObject_GetAttr
...
finalize_modules
_Py_Finalize
Root cause
During finalization, greenlet 3.4.0 correctly returns NULL from PyGreenlet_GetCurrent(), but it does not set an exception. gevent's Cython code follows the NULL error path and calls __Pyx_AddTraceback; CPython then enters traceback handling without a current exception and segfaults.
The one-line fix gives the NULL return the normal C API error contract. The result is the same controlled unraisable RuntimeError: greenlet is being finalized produced by greenlet 3.5.0 instead of a process crash.
Validation
- greenlet 3.4.0: segfaulted 5/5 times
- greenlet 3.4.0 plus the one-line patch: exited normally 10/10 times
- greenlet 3.5.0: exited normally 5/5 times
Both patched 3.4.0 and 3.5.0 produce the same unraisable RuntimeError from the finalizer.
If a 3.4 maintenance branch is created, I would be happy to submit the backport and regression test as a PR. Binary wheels matching the 3.4.0 platform matrix would be especially helpful for pinned deployments.
Related: #507, #508.
Summary
Would you consider publishing greenlet 3.4.1 with the
PyGreenlet_GetCurrent()error-setting fix that is already present in 3.5.0?I realize #508 intentionally became 3.5.0 because removing the
atexitcallback changed shutdown behavior. I am not asking to backport that broader behavior change. The requested 3.4.1 change is only this line from004e1e9:static PyGreenlet* PyGreenlet_GetCurrent(void) { if (greenlet::IsShuttingDown()) { + PyErr_SetString(PyExc_RuntimeError, "greenlet is being finalized"); return nullptr; }We have observed crashes in services using greenlet 3.4.0. Upgrading to the 3.5 line resolves the issue, but the fix itself appears small enough to backport to the 3.4 line without bringing in the broader shutdown behavior changes from 3.5. A 3.4.1 patch release could therefore provide a narrowly scoped fix for users who have not yet upgraded.
Reproducer
Environment:
For example:
This reproduces 5/5 times here. No tracing or instrumentation library is imported.
The native stack ends in:
Root cause
During finalization, greenlet 3.4.0 correctly returns
NULLfromPyGreenlet_GetCurrent(), but it does not set an exception. gevent's Cython code follows theNULLerror path and calls__Pyx_AddTraceback; CPython then enters traceback handling without a current exception and segfaults.The one-line fix gives the
NULLreturn the normal C API error contract. The result is the same controlled unraisableRuntimeError: greenlet is being finalizedproduced by greenlet 3.5.0 instead of a process crash.Validation
Both patched 3.4.0 and 3.5.0 produce the same unraisable
RuntimeErrorfrom the finalizer.If a 3.4 maintenance branch is created, I would be happy to submit the backport and regression test as a PR. Binary wheels matching the 3.4.0 platform matrix would be especially helpful for pinned deployments.
Related: #507, #508.