From 8d109cb0436e76448b2a413833bc867d490f6cca Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Thu, 8 May 2008 04:26:35 +0000 Subject: Antoine Pitrou's patch for bug 2507; exception state lives too long in 3.0. --- Lib/test/test_exceptions.py | 31 +++++++++++++++++++++++++++++-- Python/ceval.c | 13 +++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index ae4687f..0574356 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -4,6 +4,7 @@ import os 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 --git a/Python/ceval.c b/Python/ceval.c index bac8278..defd002 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1477,6 +1477,19 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) "'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; -- cgit v0.12