diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2013-12-13 02:01:38 +0100 |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2013-12-13 02:01:38 +0100 |
commit | fdeb6ec45ab898e2783e44495a756f56b42f4a80 (patch) | |
tree | 572112b73b25f09bea638391bd351375a7ceb9a0 /Lib/test | |
parent | 62ca10051b5aa07b86807a50674dbef4cace22f7 (diff) | |
download | cpython-git-fdeb6ec45ab898e2783e44495a756f56b42f4a80.tar.gz |
Issue #14432: Remove the thread state field from the frame structure. Fix a
crash when a generator is created in a C thread that is destroyed while the
generator is still used. The issue was that a generator contains a frame, and
the frame kept a reference to the Python state of the destroyed C thread. The
crash occurs when a trace function is setup.
Diffstat (limited to 'Lib/test')
-rw-r--r-- | Lib/test/test_sys.py | 2 | ||||
-rw-r--r-- | Lib/test/test_threading.py | 38 |
2 files changed, 39 insertions, 1 deletions
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 9b11f58f8d..177b92ed70 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -818,7 +818,7 @@ class SizeofTest(unittest.TestCase): nfrees = len(x.f_code.co_freevars) extras = x.f_code.co_stacksize + x.f_code.co_nlocals +\ ncells + nfrees - 1 - check(x, vsize('13P3ic' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) + check(x, vsize('12P3ic' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) # function def func(): pass check(func, size('12P')) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index a84577cc0f..73839e7936 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -662,6 +662,44 @@ class ThreadTests(BaseTestCase): self.assertRegex(err.rstrip(), b"^sys:1: ResourceWarning: unclosed file ") + def test_frame_tstate_tracing(self): + # Issue #14432: Crash when a generator is created in a C thread that is + # destroyed while the generator is still used. The issue was that a + # generator contains a frame, and the frame kept a reference to the + # Python state of the destroyed C thread. The crash occurs when a trace + # function is setup. + + def noop_trace(frame, event, arg): + # no operation + return noop_trace + + def generator(): + while 1: + yield "genereator" + + def callback(): + if callback.gen is None: + callback.gen = generator() + return next(callback.gen) + callback.gen = None + + old_trace = sys.gettrace() + sys.settrace(noop_trace) + try: + # Install a trace function + threading.settrace(noop_trace) + + # Create a generator in a C thread which exits after the call + _testcapi.call_in_temporary_c_thread(callback) + + # Call the generator in a different Python thread, check that the + # generator didn't keep a reference to the destroyed thread state + for test in range(3): + # The trace function is still called here + callback() + finally: + sys.settrace(old_trace) + class ThreadJoinOnShutdown(BaseTestCase): |