-
-
Notifications
You must be signed in to change notification settings - Fork 33.4k
Description
Bug report
Python objects can be resurrected due to side effects of their finalizers (__del__ functions). The relevant code is in PyObject_CallFinalizerFromDealloc in object.c (as well as in test code in Modules/_testcapi/gc.c):
Lines 510 to 514 in eb53750
| /* tp_finalize resurrected it! Make it look like the original Py_DECREF | |
| * never happened. */ | |
| Py_ssize_t refcnt = Py_REFCNT(self); | |
| _Py_NewReferenceNoTotal(self); | |
| Py_SET_REFCNT(self, refcnt); |
Note that the Py_REFCNT()/Py_SET_REFCNT() calls undo the re-initialization of the refcount, so that the effect (in the default builds) is just to:
- Call
_PyTraceMalloc_NewReferenceif tracemalloc is enabled - Call
_Py_AddToAllObjectsifPy_TRACE_REFSis enabled
The problem is that the free-threaded builds do additional initialization in _Py_NewReferenceNoTotal. For example, they initialize the ob_gc_bits field, which will keep track of if the object has been finalized. We don't want to re-initialize that here.
We should add an internal-only function that only does the two desired calls (and not the other re-initialization) and call that from PyObject_CallFinalizerFromDealloc and the test in Modules/_testcapi/gc.c instead of re-purposing _Py_NewReferenceNoTotal.