diff Python/errors.c @ 48474:2ee09afee126

implement chained exception tracebacks patch from Antoine Pitrou #3112
author Benjamin Peterson <benjamin@python.org>
date Tue, 15 Jul 2008 15:32:09 +0000
parents 7ba7901dad7f
children 1ec38b707cd6
line wrap: on
line diff
--- a/Python/errors.c	Tue Jul 15 14:31:20 2008 +0000
+++ b/Python/errors.c	Tue Jul 15 15:32:09 2008 +0000
@@ -84,8 +84,23 @@
 				return;
 			value = fixed_value;
 		}
-		Py_INCREF(tstate->exc_value);
-		PyException_SetContext(value, tstate->exc_value);
+		/* Avoid reference cycles through the context chain.
+		   This is O(chain length) but context chains are
+		   usually very short. Sensitive readers may try
+		   to inline the call to PyException_GetContext. */
+		if (tstate->exc_value != value) {
+			PyObject *o = tstate->exc_value, *context;
+			while ((context = PyException_GetContext(o))) {
+				Py_DECREF(context);
+				if (context == value) {
+					PyException_SetContext(o, NULL);
+					break;
+				}
+				o = context;
+			}
+			Py_INCREF(tstate->exc_value);
+			PyException_SetContext(value, tstate->exc_value);
+		}
 	}
 	if (value != NULL && PyExceptionInstance_Check(value))
 		tb = PyException_GetTraceback(value);
@@ -160,6 +175,9 @@
 
 /* Used in many places to normalize a raised exception, including in
    eval_code2(), do_raise(), and PyErr_Print()
+
+   XXX: should PyErr_NormalizeException() also call
+	    PyException_SetTraceback() with the resulting value and tb?
 */
 void
 PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)