diff -r 12e337631b2b Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py Fri May 02 03:19:50 2008 +0200 +++ b/Lib/test/test_exceptions.py Fri May 02 22:26:35 2008 +0200 @@ -4,6 +4,7 @@ import sys import unittest import pickle +import weakref from test.test_support import TESTFN, unlink, run_unittest @@ -400,8 +401,9 @@ 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 @@ 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 12e337631b2b Python/ceval.c --- a/Python/ceval.c Fri May 02 03:19:50 2008 +0200 +++ b/Python/ceval.c Fri May 02 22:26:35 2008 +0200 @@ -1477,6 +1477,19 @@ "'finally' pops bad exception"); why = WHY_EXCEPTION; } + /* + Make sure the exception state is cleaned up before + the end of an except block. This ensures objects + referenced by the exception state are not kept + alive 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;