Skip to content

Fix Python object resurrection on free-threaded builds #113750

Closed
@colesbury

Description

@colesbury

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):

cpython/Objects/object.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:

  1. Call _PyTraceMalloc_NewReference if tracemalloc is enabled
  2. Call _Py_AddToAllObjects if Py_TRACE_REFS is 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.

Linked PRs

Metadata

Metadata

Assignees

Labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions