Antoine Pitrou's patch for bug 2507; exception state lives too long in

3.0.
This commit is contained in:
Barry Warsaw 2008-05-08 04:26:35 +00:00
parent 96de30ae1e
commit 8d109cb043
2 changed files with 42 additions and 2 deletions

View File

@ -4,6 +4,7 @@ import os
import sys import sys
import unittest import unittest
import pickle import pickle
import weakref
from test.test_support import TESTFN, unlink, run_unittest 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')))
self.failUnless(str(Exception('a'))) self.failUnless(str(Exception('a')))
def testExceptionCleanup(self): def testExceptionCleanupNames(self):
# Make sure "except V as N" exceptions are cleaned up properly # Make sure the local variable bound to the exception instance by
# an "except" statement is only visible inside the except block.
try: try:
raise Exception() raise Exception()
@ -410,6 +412,31 @@ class ExceptionTests(unittest.TestCase):
del e del e
self.failIf('e' in locals()) 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(): def test_main():
run_unittest(ExceptionTests) run_unittest(ExceptionTests)

View File

@ -1477,6 +1477,19 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
"'finally' pops bad exception"); "'finally' pops bad exception");
why = WHY_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); Py_DECREF(v);
break; break;