bpo-28737: Document when tp_dealloc should call PyObject_GC_UnTrack() (GH-29246)

Objects that support garbage collection ("container" objects) should
call PyObject_GC_UnTrack() from their destructors before clearing any
fields which may point to other "container" objects.
This commit is contained in:
Sam Gross 2021-10-27 15:15:13 -04:00 committed by GitHub
parent 4776b07d17
commit 35e1ff38ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 33 additions and 9 deletions

View file

@ -33,6 +33,14 @@ Constructors for container types must conform to two rules:
#. Once all the fields which may contain references to other containers are
initialized, it must call :c:func:`PyObject_GC_Track`.
Similarly, the deallocator for the object must conform to a similar pair of
rules:
#. Before fields which refer to other containers are invalidated,
:c:func:`PyObject_GC_UnTrack` must be called.
#. The object's memory must be deallocated using :c:func:`PyObject_GC_Del`.
.. warning::
If a type adds the Py_TPFLAGS_HAVE_GC, then it *must* implement at least
a :c:member:`~PyTypeObject.tp_traverse` handler or explicitly use one
@ -100,14 +108,6 @@ Constructors for container types must conform to two rules:
.. versionadded:: 3.9
Similarly, the deallocator for the object must conform to a similar pair of
rules:
#. Before fields which refer to other containers are invalidated,
:c:func:`PyObject_GC_UnTrack` must be called.
#. The object's memory must be deallocated using :c:func:`PyObject_GC_Del`.
.. c:function:: void PyObject_GC_Del(void *op)

View file

@ -668,6 +668,18 @@ and :c:type:`PyType_Type` effectively act as defaults.)
:c:func:`PyObject_GC_Del` if the instance was allocated using
:c:func:`PyObject_GC_New` or :c:func:`PyObject_GC_NewVar`.
If the type supports garbage collection (has the :const:`Py_TPFLAGS_HAVE_GC`
flag bit set), the destructor should call :c:func:`PyObject_GC_UnTrack`
before clearing any member fields.
.. code-block:: c
static void foo_dealloc(foo_object *self) {
PyObject_GC_UnTrack(self);
Py_CLEAR(self->ref);
Py_TYPE(self)->tp_free((PyObject *)self);
}
Finally, if the type is heap allocated (:const:`Py_TPFLAGS_HEAPTYPE`), the
deallocator should decrement the reference count for its type object after
calling the type deallocator. In order to avoid dangling pointers, the

View file

@ -73,7 +73,19 @@ function::
newdatatype_dealloc(newdatatypeobject *obj)
{
free(obj->obj_UnderlyingDatatypePtr);
Py_TYPE(obj)->tp_free(obj);
Py_TYPE(obj)->tp_free((PyObject *)obj);
}
If your type supports garbage collection, the destructor should call
:c:func:`PyObject_GC_UnTrack` before clearing any member fields::
static void
newdatatype_dealloc(newdatatypeobject *obj)
{
PyObject_GC_UnTrack(obj);
Py_CLEAR(obj->other_obj);
...
Py_TYPE(obj)->tp_free((PyObject *)obj);
}
.. index::