From 610719022f3c9d4cafc1771aede4a2538bea59db Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Wed, 15 Sep 2021 12:44:19 -0400 Subject: [PATCH 1/6] Document that error indicator may be set in tp_dealloc Signed-off-by: Edward Z. Yang --- Doc/c-api/typeobj.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index b17fb22b694951..e7c9b13646cf47 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -668,6 +668,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`. + If you may call functions that may set the error indicator, you must + use :c:func:`PyErr_Fetch` and :c:func:`PyErr_Restore` to ensure you + don't clobber a preexisting error indicator (the deallocation could + have occurred while processing a different error): + + .. code-block:: c + + static void foo_dealloc(foo_object *self) { + PyObject *et, *ev, *etb; + PyErr_Fetch(&et, &ev, &etb); + ... + PyErr_Restore(et, ev, etb); + } + 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 From 3d7a84273724b5820c0392d32c7b1fa10bcd122d Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Wed, 15 Sep 2021 13:07:36 -0400 Subject: [PATCH 2/6] add blurb Signed-off-by: Edward Z. Yang --- .../next/Documentation/2021-09-15-13-07-25.bpo-45210.RtGk7i.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Documentation/2021-09-15-13-07-25.bpo-45210.RtGk7i.rst diff --git a/Misc/NEWS.d/next/Documentation/2021-09-15-13-07-25.bpo-45210.RtGk7i.rst b/Misc/NEWS.d/next/Documentation/2021-09-15-13-07-25.bpo-45210.RtGk7i.rst new file mode 100644 index 00000000000000..ce3eba154ba6aa --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2021-09-15-13-07-25.bpo-45210.RtGk7i.rst @@ -0,0 +1,2 @@ +Document that error indicator may be set in tp_dealloc, and how to avoid +clobbering it. From f068c4ede7a63594c539cb75e09349aaf76401e6 Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Tue, 5 Apr 2022 22:13:02 -0400 Subject: [PATCH 3/6] Update typeobj.rst --- Doc/c-api/typeobj.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 8b8f7240d26c0b..11b0bf1a60fe77 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -682,6 +682,10 @@ and :c:type:`PyType_Type` effectively act as defaults.) PyErr_Restore(et, ev, etb); } + The dealloc handler itself must not raise an exception; if it hits an error + case it should call :c:func:`PyErr_WriteUnraisable` to log (and clear) an + unraisable exception. + 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. From 6c718859c3e1850cdef4949316f3f5232780f7ab Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Fri, 6 Jun 2025 09:29:58 -0400 Subject: [PATCH 4/6] Don't use deprecated PyErr_Fetch Signed-off-by: Edward Z. Yang --- Doc/c-api/typeobj.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index f2022842704516..f573e7c66ae4ac 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -686,18 +686,18 @@ and :c:data:`PyType_Type` effectively act as defaults.) instance, and call the type's :c:member:`~PyTypeObject.tp_free` function to free the object itself. - If you may call functions that may set the error indicator, you must - use :c:func:`PyErr_Fetch` and :c:func:`PyErr_Restore` to ensure you - don't clobber a preexisting error indicator (the deallocation could - have occurred while processing a different error): + If you may call functions that may set the error indicator, you must use + :c:func:`PyErr_GetRaisedException` and :c:func:`PyErr_SetRaisedException` + to ensure you don't clobber a preexisting error indicator (the deallocation + could have occurred while processing a different error): .. code-block:: c static void foo_dealloc(foo_object *self) { PyObject *et, *ev, *etb; - PyErr_Fetch(&et, &ev, &etb); + PyObject *exc = PyErr_GetRaisedException(); ... - PyErr_Restore(et, ev, etb); + PyErr_SetRaisedException(exc); } The dealloc handler itself must not raise an exception; if it hits an error From 3e62ace3c4227102163264e7f44e41f1c89250c1 Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Fri, 6 Jun 2025 13:41:03 -0400 Subject: [PATCH 5/6] Update Doc/c-api/typeobj.rst Co-authored-by: Victor Stinner --- Doc/c-api/typeobj.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index f573e7c66ae4ac..0fa92e08dc5643 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -701,7 +701,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) } The dealloc handler itself must not raise an exception; if it hits an error - case it should call :c:func:`PyErr_WriteUnraisable` to log (and clear) an + case it should call :c:func:`PyErr_FormatUnraisable` to log (and clear) an unraisable exception. No guarantees are made about when an object is destroyed, except: From 6afd215e7c2730c1d5059a1cd909f170d752a976 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 9 Jun 2025 10:50:11 +0200 Subject: [PATCH 6/6] Update Doc/c-api/typeobj.rst --- Doc/c-api/typeobj.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 0fa92e08dc5643..af2bead3bb5004 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -693,7 +693,9 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. code-block:: c - static void foo_dealloc(foo_object *self) { + static void + foo_dealloc(foo_object *self) + { PyObject *et, *ev, *etb; PyObject *exc = PyErr_GetRaisedException(); ...