From 92a9087b3083d72458cd411e6a0f955f04951e5b Mon Sep 17 00:00:00 2001 From: Ammar Askar Date: Tue, 17 Sep 2019 20:10:21 -0400 Subject: [PATCH 1/2] bpo-38206: Clarify tp_dealloc requirements for heap allocated types. --- Doc/c-api/type.rst | 3 ++- Doc/c-api/typeobj.rst | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index 6416951ac5a94c..239355a802413e 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -118,7 +118,8 @@ The following functions and structs are used to create .. c:function:: PyObject* PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) - Creates and returns a heap type object from the *spec*. + Creates and returns a heap type object from the *spec* + (:const:`Py_TPFLAGS_HEAPTYPE`). If *bases* is a tuple, the created heap type contains all types contained in it as base types. diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 7c7a79129ccca2..03459d0a8451dd 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -654,8 +654,8 @@ and :c:type:`PyType_Type` effectively act as defaults.) the instance is still in existence, but there are no references to it. The destructor function should free all references which the instance owns, free all memory buffers owned by the instance (using the freeing function corresponding - to the allocation function used to allocate the buffer), and finally (as its - last action) call the type's :c:member:`~PyTypeObject.tp_free` function. If the type is not + to the allocation function used to allocate the buffer), and then call the + type's :c:member:`~PyTypeObject.tp_free` function. If the type is not subtypable (doesn't have the :const:`Py_TPFLAGS_BASETYPE` flag bit set), it is permissible to call the object deallocator directly instead of via :c:member:`~PyTypeObject.tp_free`. The object deallocator should be the one used to allocate the @@ -664,6 +664,10 @@ 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`. + Finally, if the type is heap allocated (:const:`Py_TPFLAGS_HEAPTYPE` or + built with :c:func:`PyType_FromSpec`), the deallocator should decrement the + reference count for its type object. + **Inheritance:** This field is inherited by subtypes. From 291258b9fa01c2298c9d2802d0bbba3eb8e2289b Mon Sep 17 00:00:00 2001 From: Ammar Askar Date: Thu, 19 Sep 2019 17:23:28 -0400 Subject: [PATCH 2/2] Incorporate suggestions from review --- Doc/c-api/typeobj.rst | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 03459d0a8451dd..bb767500743098 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -654,9 +654,9 @@ and :c:type:`PyType_Type` effectively act as defaults.) the instance is still in existence, but there are no references to it. The destructor function should free all references which the instance owns, free all memory buffers owned by the instance (using the freeing function corresponding - to the allocation function used to allocate the buffer), and then call the - type's :c:member:`~PyTypeObject.tp_free` function. If the type is not - subtypable (doesn't have the :const:`Py_TPFLAGS_BASETYPE` flag bit set), it is + to the allocation function used to allocate the buffer), and call the type's + :c:member:`~PyTypeObject.tp_free` function. If the type is not subtypable + (doesn't have the :const:`Py_TPFLAGS_BASETYPE` flag bit set), it is permissible to call the object deallocator directly instead of via :c:member:`~PyTypeObject.tp_free`. The object deallocator should be the one used to allocate the instance; this is normally :c:func:`PyObject_Del` if the instance was allocated @@ -664,9 +664,20 @@ 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`. - Finally, if the type is heap allocated (:const:`Py_TPFLAGS_HEAPTYPE` or - built with :c:func:`PyType_FromSpec`), the deallocator should decrement the - reference count for its type object. + 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 + recommended way to achieve this is: + + .. code-block:: c + + static void foo_dealloc(foo_object *self) { + PyTypeObject *tp = Py_TYPE(self); + // free references and buffers here + tp->tp_free(self); + Py_DECREF(tp); + } + **Inheritance:** @@ -1025,7 +1036,8 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. data:: Py_TPFLAGS_HEAPTYPE - This bit is set when the type object itself is allocated on the heap. In this + This bit is set when the type object itself is allocated on the heap, for + example, types created dynamically using :c:func:`PyType_FromSpec`. In this case, the :attr:`ob_type` field of its instances is considered a reference to the type, and the type object is INCREF'ed when a new instance is created, and DECREF'ed when an instance is destroyed (this does not apply to instances of