diff --git a/Lib/test/crashers/mutation_inside_cyclegc.py b/Lib/test/crashers/mutation_inside_cyclegc.py deleted file mode 100644 index 2b67398bccce23..00000000000000 --- a/Lib/test/crashers/mutation_inside_cyclegc.py +++ /dev/null @@ -1,31 +0,0 @@ - -# The cycle GC collector can be executed when any GC-tracked object is -# allocated, e.g. during a call to PyList_New(), PyDict_New(), ... -# Moreover, it can invoke arbitrary Python code via a weakref callback. -# This means that there are many places in the source where an arbitrary -# mutation could unexpectedly occur. - -# The example below shows list_slice() not expecting the call to -# PyList_New to mutate the input list. (Of course there are many -# more examples like this one.) - - -import weakref - -class A(object): - pass - -def callback(x): - del lst[:] - - -keepalive = [] - -for i in range(100): - lst = [str(i)] - a = A() - a.cycle = a - keepalive.append(weakref.ref(a, callback)) - del a - while lst: - keepalive.append(lst[:]) diff --git a/Lib/test/crashers/trace_at_recursion_limit.py b/Lib/test/crashers/trace_at_recursion_limit.py deleted file mode 100644 index acd863f5509c49..00000000000000 --- a/Lib/test/crashers/trace_at_recursion_limit.py +++ /dev/null @@ -1,27 +0,0 @@ -""" -From http://bugs.python.org/issue6717 - -A misbehaving trace hook can trigger a segfault by exceeding the recursion -limit. -""" -import sys - - -def x(): - pass - -def g(*args): - if True: # change to True to crash interpreter - try: - x() - except: - pass - return g - -def f(): - print(sys.getrecursionlimit()) - f() - -sys.settrace(g) - -f() diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py index b5140057a69d36..856f662ee847b9 100644 --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py @@ -1568,6 +1568,45 @@ def test_ast_fini(self): assert_python_ok("-c", code) +@requires_gil_enabled("This test hangs and occasionally segfaults on the Free-threading build") +class MutationInsideCycleGCTests(unittest.TestCase): + def setUp(self): + # This test requires the gc to be enabled. + gc.enable() + self.addCleanup(gc.disable) + + def test_does_not_crash(self): + # Moved from Lib/test/crashers as it does not crash anymore. + # This test ensures that the code does not start crashing again. + # Original comment: + + # The cycle GC collector can be executed when any GC-tracked object is + # allocated, e.g. during a call to PyList_New(), PyDict_New(), ... + # Moreover, it can invoke arbitrary Python code via a weakref callback. + # This means that there are many places in the source where an arbitrary + # mutation could unexpectedly occur. + + # The example below shows list_slice() not expecting the call to + # PyList_New to mutate the input list. (Of course there are many + # more examples like this one.) + class A(object): + pass + + def callback(x): + del lst[:] + + keepalive = [] + + for i in range(100): + lst = [str(i)] + a = A() + a.cycle = a + keepalive.append(weakref.ref(a, callback)) + del a + while lst: + keepalive.append(lst[:]) + + def setUpModule(): global enabled, debug enabled = gc.isenabled() diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index b3685a91c57ee7..6a50270d96385c 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -3135,5 +3135,37 @@ def func(arg = 1): sys.settrace(None) +class TestTraceAtRecursionLimit(unittest.TestCase): + def setUp(self): + self.addCleanup(sys.settrace, sys.gettrace()) + + def test_does_not_crash(self): + # Moved from Lib/test/crashers as it does not crash anymore. + # This test ensures that the code does not start crashing again. + # Original comment: + + # From http://bugs.python.org/issue6717 + + # A misbehaving trace hook can trigger a segfault by exceeding the recursion + # limit. + def x(): + pass + + def g(*args): + if True: + try: + x() + except: + pass + return g + + def f(): + f() + + sys.settrace(g) + with self.assertRaises(RecursionError): + f() + + if __name__ == "__main__": unittest.main()