On 16.06.2020 03:15, Victor Stinner wrote:
Le lun. 15 juin 2020 à 17:39, M.-A. Lemburg mal@egenix.com a écrit :
Do we have any evidence such objects exist in the real world? In other words, is this enough of a problem that it needs new public API?
Well, if you search on Github, you find some 18k hits. Many are from forks of the Python source code, but there are also a number of hits in stackless,
Stackless is a fork of Python. Occurrences in Python code base should be ignored.
While true, the call is in a Stackless util file: https://github.com/swolchok/dspython/blob/8117b6a4a3f3aee7a7586d99aeadbee9ec...
nuitka, pyuv, PyPy's cpyext and numpy from a quick inspection.
I cannot find _Py_ForgetReference() or _Py_NewReference() in numpy code base (I checked the master branch).
https://github.com/henjo/numpy/blob/cd73a18cdbdf679f2f74b7b21d2951bf124d80fb...
Well, cpyext only implements functions to be compatible with CPython.
Yeah, it looks a lot like a copy of Python's structseq.c.
nuitka copied/pasted resize_compact() of CPython Objects/unicodeobject.c: https://github.com/Nuitka/Nuitka/blob/82d2da2f639483ae9b74ad7a765a66e45ab367...
... _Py_DEC_REFTOTAL; _Py_ForgetReference(unicode); ...
It's a micro-optimization to resize a Python immutable string in-place. It should be avoided outside CPython code base: use public PyUnicode_Resize() C API function.
pyuv: https://github.com/saghul/pyuv/blob/39342fc2fd688f2fb2120d3092dd9cf52f537de2...
Oh wow, that's ugly code which relies on so many implementation details! It is unlikely to build on the master branch of Python:
/* Taken from http://bugs.python.org/issue8212
- A function to do the necessary adjustments if we find that code
- run during a tp_dealloc or tp_free has resurrected an
- object. It adjusts the total reference count and adds a new
- reference to the type. */ static void resurrect_object(PyObject *self) { /* The object lives again. We must now undo the _Py_ForgetReference
- done in _Py_Dealloc in object.c. */ Py_ssize_t refcnt = Py_REFCNT(self); ASSERT(Py_REFCNT(self) != 0); _Py_NewReference(self); Py_REFCNT(self) = refcnt; /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so
- we need to undo that. */ #ifdef _Py_DEC_REFTOTAL _Py_DEC_REFTOTAL; #endif /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object
- chain, so no more to do there.
- If COUNT_ALLOCS, the original decref bumped tp_frees, and
- _Py_NewReference bumped tp_allocs: both of those need to be
- undone. */ #ifdef COUNT_ALLOCS --Py_TYPE(self)->tp_frees; --Py_TYPE(self)->tp_allocs; #endif
/* When called from a heap type's dealloc (subtype_dealloc avove), the type will be
- decref'ed on return. This counteracts that. There is no way to otherwise
- let subtype_dealloc know that calling a parent class' tp_dealloc slot caused
- the instance to be resurrected. */ if (PyType_HasFeature(Py_TYPE(self), Py_TPFLAGS_HEAPTYPE)) Py_INCREF(Py_TYPE(self)); return; }
tp_finalize of PEP 442 should avoid the need for such a function, but I didn't check.
Not sure why the above code is needed for libuv. It's a library implementing a fast async stack.
Do we even support resurrecting objects in tp_dealloc or tp_free ?
It can be done, of course, but seems like a rather poor design for implementing an object which cannot be deallocated. There are certainly better way of doing this (e.g. keep references to the object alive in a separate dictionary or list).
-- Marc-Andre Lemburg eGenix.com
Professional Python Services directly from the Experts (#1, Jun 16 2020)
Python Projects, Coaching and Support ... https://www.egenix.com/ Python Product Development ... https://consulting.egenix.com/
::: We implement business ideas - efficiently in both time and costs :::
eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 https://www.egenix.com/company/contact/ https://www.malemburg.com/