Description
Bug report
Bug description:
The code in _Py_SetImmortal
must be run on the thread that originally allocated the object. If this is not the case, then a race between Py_INCREF
can cause the _Py_SetImmortal
to be ignored.
cpython/Include/internal/pycore_object.h
Lines 128 to 139 in 2e7577b
Example sequence:
- Allocating thread begins an
_Py_Incref
. - Allocating thread detects it should perform inc ref on
ob_ref_local
, and calculates new value. - Non-allocating thread runs all of
_Py_SetImmortal
. - Allocating thread completes incref with assignment to
ob_ref_local
, and unsets the value from immortal.
In the nogil fork, there is some defensive code on other operations that need to be run on the allocating thread, e.g.
_PyObject_SetDeferredRefcount(PyObject *op)
{
assert(_Py_ThreadLocal(op) && "non thread-safe");
I think something like this should occur inside _Py_SetImmortal
.
It looks like _Py_SetImmortal
is not exposed outside the runtime. However, PEP 683, says:
Then setting any object’s refcount to _Py_IMMORTAL_REFCNT makes it immortal.
This implies there is an intent to expose it, and with the changes to nogil. It seems that this should be exposed as an explicit operation, rather than by setting the ref count directly.
CC @ericsnowcurrently @colesbury
P.S. I am happy to PR any required changes.
CPython versions tested on:
CPython main branch
Operating systems tested on:
No response