diff -r adc2f5003ea3 Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py Sat Mar 29 06:06:52 2008 +0100 +++ b/Lib/test/test_exceptions.py Sun Mar 30 00:10:32 2008 +0100 @@ -4,6 +4,7 @@ import sys import sys import unittest import pickle +import weakref from test.test_support import TESTFN, unlink, run_unittest @@ -400,8 +401,9 @@ class ExceptionTests(unittest.TestCase): self.failUnless(str(Exception('a'))) self.failUnless(str(Exception('a'))) - def testExceptionCleanup(self): - # Make sure "except V as N" exceptions are cleaned up properly + def testExceptionCleanupNames(self): + # Make sure the local variable bound to the exception instance by + # an "except" statement is only visible inside the except block. try: raise Exception() @@ -410,6 +412,31 @@ class ExceptionTests(unittest.TestCase): del e self.failIf('e' in locals()) + def testExceptionCleanupState(self): + # Make sure exception state is cleaned up as soon as the except + # block is left. See #2507 + + class MyException(Exception): + def __init__(self, obj): + self.obj = obj + class MyObj: + pass + + def inner_raising_func(): + # Create some references in exception value and traceback + local_ref = obj + raise MyException(obj) + + obj = MyObj() + wr = weakref.ref(obj) + try: + inner_raising_func() + except MyException as e: + pass + obj = None + obj = wr() + self.failUnless(obj is None, "%s" % obj) + def test_main(): run_unittest(ExceptionTests) diff -r adc2f5003ea3 Python/ceval.c --- a/Python/ceval.c Sat Mar 29 06:06:52 2008 +0100 +++ b/Python/ceval.c Sun Mar 30 00:10:32 2008 +0100 @@ -1477,6 +1477,18 @@ PyEval_EvalFrameEx(PyFrameObject *f, int "'finally' pops bad exception"); why = WHY_EXCEPTION; } + /* + Make sure the exception state is cleaned up, even if there + is a thread switch before we leave the frame. This ensures + references to the exception state are not kept too long. + See #2507. + */ + if (tstate->frame->f_exc_type != NULL) + reset_exc_info(tstate); + else { + assert(tstate->frame->f_exc_value == NULL); + assert(tstate->frame->f_exc_traceback == NULL); + } Py_DECREF(v); break;