summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/api/api.tex11
-rw-r--r--Include/pyerrors.h1
-rw-r--r--Modules/gcmodule.c11
-rw-r--r--Objects/classobject.c21
-rw-r--r--Python/errors.c27
5 files changed, 50 insertions, 21 deletions
diff --git a/Doc/api/api.tex b/Doc/api/api.tex
index 1f20129..c8731c9 100644
--- a/Doc/api/api.tex
+++ b/Doc/api/api.tex
@@ -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}}
diff --git a/Include/pyerrors.h b/Include/pyerrors.h
index 6e60353..311e258 100644
--- a/Include/pyerrors.h
+++ b/Include/pyerrors.h
@@ -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);
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index 57ee7b9..889ae25 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -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));
diff --git a/Objects/classobject.c b/Objects/classobject.c
index 0b595b9..615c8ba 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -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);
diff --git a/Python/errors.c b/Python/errors.c
index 8486423..355ec9c 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -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);
+}