From d979c72160025d7163e5d75eb4e676bfaedfea20 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Sat, 27 Jul 2013 14:06:56 -0700 Subject: [PATCH] add a test for issue #17669 (closes #18565) Patch from Phil Connell. --- Lib/test/test_pep380.py | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_pep380.py b/Lib/test/test_pep380.py index f3eed4353b9..4a43b7d62b5 100644 --- a/Lib/test/test_pep380.py +++ b/Lib/test/test_pep380.py @@ -13,7 +13,7 @@ import sys import inspect import parser -from test.support import captured_stderr +from test.support import captured_stderr, disable_gc, gc_collect class TestPEP380Operation(unittest.TestCase): """ @@ -954,6 +954,45 @@ class TestPEP380Operation(unittest.TestCase): list(gen()) 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(): from test import support