Antoine Pitrou's patch for bug 2507; exception state lives too long in
3.0.
This commit is contained in:
parent
96de30ae1e
commit
8d109cb043
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue