]> granicus.if.org Git - python/commitdiff
refactor __del__ exception handler into PyErr_WriteUnraisable
authorJeremy Hylton <jeremy@alum.mit.edu>
Fri, 1 Sep 2000 02:47:25 +0000 (02:47 +0000)
committerJeremy Hylton <jeremy@alum.mit.edu>
Fri, 1 Sep 2000 02:47:25 +0000 (02:47 +0000)
add sanity check to gc: if an exception occurs during GC, call
PyErr_WriteUnraisable and then call Py_FatalEror.

Doc/api/api.tex
Include/pyerrors.h
Modules/gcmodule.c
Objects/classobject.c
Python/errors.c

index 1f20129e2563ec812011f0bf341e795784f0349e..c8731c97e930d89eb07fd2f3785af6f8c5876288 100644 (file)
@@ -972,6 +972,17 @@ alternate base class.  The \var{dict} argument can be used to specify
 a dictionary of class variables and methods.
 \end{cfuncdesc}
 
+\begin{cfuncdesc}{void}{PyErr_WriteUnraisable}{PyObject *obj}
+This utility function prints a warning message to \var{sys.stderr}
+when an exception has been set but it is impossible for the
+interpreter to actually raise the exception.  It is used, for example,
+when an exception occurs in an \member{__del__} method.
+
+The function is called with a single argument \var{obj} that
+identifies where the context in which the unraisable exception
+occurred.  The repr of \var{obj} will be printed in the warning
+message.
+\end{cfuncdesc}
 
 \section{Standard Exceptions \label{standardExceptions}}
 
index 6e6035334d4e92b42987e3165347aec2ac9b7a88..311e258a3bf5cedd85bbe407960e4f42417a0bcb 100644 (file)
@@ -92,6 +92,7 @@ extern DL_IMPORT(void) _PyErr_BadInternalCall(char *filename, int lineno);
 /* Function to create a new exception */
 DL_IMPORT(PyObject *) PyErr_NewException(char *name, PyObject *base,
                                          PyObject *dict);
+extern DL_IMPORT(void) PyErr_WriteUnraisable(PyObject *);
 
 /* In sigcheck.c or signalmodule.c */
 extern DL_IMPORT(int) PyErr_CheckSignals(void);
index 57ee7b914348b4aa79647eb488d16b306bc36010..889ae25a95088a195619ed5ca23508e0b68d3174 100644 (file)
@@ -57,11 +57,13 @@ static int allocated;
                                DEBUG_UNCOLLECTABLE | \
                                DEBUG_INSTANCES | \
                                DEBUG_OBJECTS
-static int debug = 0;
+static int debug;
 
 /* list of uncollectable objects */
 static PyObject *garbage;
 
+/* Python string to use if unhandled exception occurs */
+static PyObject *gc_str;
 
 /*** list functions ***/
 
@@ -435,6 +437,10 @@ collect(PyGC_Head *young, PyGC_Head *old)
         * this if they insist on creating this type of structure. */
        handle_finalizers(&finalizers, old);
 
+       if (PyErr_Occurred()) {
+               PyErr_WriteUnraisable(gc_str);
+               Py_FatalError("unexpected exception during garbage collection");
+       }
        allocated = 0;
        return n+m;
 }
@@ -699,6 +705,9 @@ initgc(void)
        if (garbage == NULL) {
                garbage = PyList_New(0);
        }
+       if (gc_str == NULL) {
+               gc_str = PyString_FromString("garbage collection");
+       }
        PyDict_SetItemString(d, "garbage", garbage);
        PyDict_SetItemString(d, "DEBUG_STATS",
                        PyInt_FromLong(DEBUG_STATS));
index 0b595b9090a71ba5565038d166dd7c6863f77198..615c8bab5497a7fdb85dd4bf295781e125994a2b 100644 (file)
@@ -519,26 +519,7 @@ instance_dealloc(register PyInstanceObject *inst)
        if ((del = instance_getattr2(inst, delstr)) != NULL) {
                PyObject *res = PyEval_CallObject(del, (PyObject *)NULL);
                if (res == NULL) {
-                       PyObject *f, *t, *v, *tb;
-                       PyErr_Fetch(&t, &v, &tb);
-                       f = PySys_GetObject("stderr");
-                       if (f != NULL) {
-                               PyFile_WriteString("Exception ", f);
-                               if (t) {
-                                       PyFile_WriteObject(t, f, Py_PRINT_RAW);
-                                       if (v && v != Py_None) {
-                                               PyFile_WriteString(": ", f);
-                                               PyFile_WriteObject(v, f, 0);
-                                       }
-                               }
-                               PyFile_WriteString(" in ", f);
-                               PyFile_WriteObject(del, f, 0);
-                               PyFile_WriteString(" ignored\n", f);
-                               PyErr_Clear(); /* Just in case */
-                       }
-                       Py_XDECREF(t);
-                       Py_XDECREF(v);
-                       Py_XDECREF(tb);
+                       PyErr_WriteUnraisable(del);
                }
                else
                        Py_DECREF(res);
index 8486423479ec349a0e4f61e1ca0ce27206767db1..355ec9cf7b657501b24dd3c05e7d03defb6a7e58 100644 (file)
@@ -450,3 +450,30 @@ PyErr_NewException(char *name, PyObject *base, PyObject *dict)
        Py_XDECREF(modulename);
        return result;
 }
+
+/* Call when an exception has occurred but there is no way for Python
+   to handle it.  Examples: exception in __del__ or during GC. */
+void
+PyErr_WriteUnraisable(PyObject *obj)
+{
+       PyObject *f, *t, *v, *tb;
+       PyErr_Fetch(&t, &v, &tb);
+       f = PySys_GetObject("stderr");
+       if (f != NULL) {
+               PyFile_WriteString("Exception ", f);
+               if (t) {
+                       PyFile_WriteObject(t, f, Py_PRINT_RAW);
+                       if (v && v != Py_None) {
+                               PyFile_WriteString(": ", f);
+                               PyFile_WriteObject(v, f, 0);
+                       }
+               }
+               PyFile_WriteString(" in ", f);
+               PyFile_WriteObject(obj, f, 0);
+               PyFile_WriteString(" ignored\n", f);
+               PyErr_Clear(); /* Just in case */
+       }
+       Py_XDECREF(t);
+       Py_XDECREF(v);
+       Py_XDECREF(tb);
+}