From 145b479508c7730a50e905c219e05c2b6d2450b7 Mon Sep 17 00:00:00 2001 From: Fred Drake Date: Tue, 11 Dec 2001 19:28:22 +0000 Subject: Added discussion of protecting against screwing up the exception state in an object's deallocator, including an example of how to do this. --- Doc/ext/newtypes.tex | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/Doc/ext/newtypes.tex b/Doc/ext/newtypes.tex index 17e2b25..6ae9f09 100644 --- a/Doc/ext/newtypes.tex +++ b/Doc/ext/newtypes.tex @@ -449,6 +449,11 @@ will implement. \subsection{Finalization and De-allocation} +\index{object!deallocation} +\index{deallocation, object} +\index{object!finalization} +\index{finalization, of objects} + \begin{verbatim} destructor tp_dealloc; \end{verbatim} @@ -468,6 +473,49 @@ newdatatype_dealloc(newdatatypeobject * obj) } \end{verbatim} +One important requirement of the deallocator function is that it +leaves any pending exceptions alone. This is important since +deallocators are frequently called as the interpreter unwinds the +Python stack; when the stack is unwound due to an exception (rather +than normal returns), nothing is done to protect the deallocators from +seeing that an exception has already been set. Any actions which a +deallocator performs which may cause additional Python code to be +executed may detect that an exception has been set. This can lead to +misleading errors from the interpreter. The proper way to protect +against this is to save a pending exception before performing the +unsafe action, and restoring it when done. This can be done using the +\cfunction{PyErr_Fetch()}\ttindex{PyErr_Fetch()} and +\cfunction{PyErr_Restore()}\ttindex{PyErr_Restore()} functions: + +\begin{verbatim} +static void +my_dealloc(PyObject *obj) +{ + MyObject *self = (MyObject *) obj; + PyObject *cbresult; + + if (self->my_callback != NULL) { + PyObject *err_type, *err_value, *err_traceback; + int have_error = PyErr_Occurred() ? 1 : 0; + + if (have_error) + PyErr_Fetch(&err_type, &err_value, &err_traceback); + + cbresult = PyObject_CallObject(self->my_callback, NULL); + if (cbresult == NULL) + PyErr_WriteUnraisable(); + else + Py_DECREF(cbresult); + + if (have_error) + PyErr_Restore(err_type, err_value, err_traceback); + + Py_DECREF(self->my_callback); + } + PyObject_DEL(obj); +} +\end{verbatim} + \subsection{Object Representation} -- cgit v0.12