summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_threading.py
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2013-12-13 01:17:29 (GMT)
committerVictor Stinner <victor.stinner@gmail.com>2013-12-13 01:17:29 (GMT)
commit131051079351859a5451b873667b489e2a9e9f2a (patch)
treeb57298e16e6aabf7ba5a48755cfb3e3f01e57ca5 /Lib/test/test_threading.py
parentda12adac10761439a8a3828958e970db98d7ebc8 (diff)
downloadcpython-131051079351859a5451b873667b489e2a9e9f2a.zip
cpython-131051079351859a5451b873667b489e2a9e9f2a.tar.gz
cpython-131051079351859a5451b873667b489e2a9e9f2a.tar.bz2
Issue #14432: Generator now clears the borrowed reference to the thread state
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/test_threading.py')
-rw-r--r--Lib/test/test_threading.py43
1 files changed, 43 insertions, 0 deletions
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index 0ebeb39..fee48a3 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -17,6 +17,10 @@ import weakref
import os
from test.script_helper import assert_python_ok, assert_python_failure
import subprocess
+try:
+ import _testcapi
+except ImportError:
+ _testcapi = None
from test import lock_tests
@@ -769,6 +773,45 @@ class ThreadJoinOnShutdown(BaseTestCase):
for t in threads:
t.join()
+ @unittest.skipIf(_testcapi is None, "need _testcapi module")
+ 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 ThreadingExceptionTests(BaseTestCase):
# A RuntimeError should be raised if Thread.start() is called