This commit is contained in:
Benjamin Peterson 2013-07-27 14:07:19 -07:00
commit 290371dadc
1 changed files with 40 additions and 1 deletions

View File

@ -13,7 +13,7 @@ import sys
import inspect import inspect
import parser import parser
from test.support import captured_stderr from test.support import captured_stderr, disable_gc, gc_collect
class TestPEP380Operation(unittest.TestCase): class TestPEP380Operation(unittest.TestCase):
""" """
@ -954,6 +954,45 @@ class TestPEP380Operation(unittest.TestCase):
list(gen()) list(gen())
self.assertEqual(ret, 42) self.assertEqual(ret, 42)
def test_close_with_cleared_frame(self):
# See issue #17669.
#
# Create a stack of generators: outer() delegating to inner()
# delegating to innermost(). The key point is that the instance of
# inner is created first: this ensures that its frame appears before
# the instance of outer in the GC linked list.
#
# At the gc.collect call:
# - frame_clear is called on the inner_gen frame.
# - gen_dealloc is called on the outer_gen generator (the only
# reference is in the frame's locals).
# - gen_close is called on the outer_gen generator.
# - gen_close_iter is called to close the inner_gen generator, which
# in turn calls gen_close, and gen_yf.
#
# Previously, gen_yf would crash since inner_gen's frame had been
# cleared (and in particular f_stacktop was NULL).
def innermost():
yield
def inner():
outer_gen = yield
yield from innermost()
def outer():
inner_gen = yield
yield from inner_gen
with disable_gc():
inner_gen = inner()
outer_gen = outer()
outer_gen.send(None)
outer_gen.send(inner_gen)
outer_gen.send(outer_gen)
del outer_gen
del inner_gen
gc_collect()
def test_main(): def test_main():
from test import support from test import support