From e4dced873bb6ae4a203277d036ecfa69163de231 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 22 Aug 2023 16:12:40 +0200 Subject: [PATCH] gh-108297: Update test_crashers * Rename Lib/test/crashers/ to Lib/test/test_crashers/. * Move Lib/test/test_crashers.py to Lib/test/test_crashers/__init__.py. * test_crashers is no longer skipped and makes sure that scripts do crash, and no simply fail with a non-zero exit code. * Update bogus_code_obj.py to use CodeType.replace(). * Remove Lib/test/crashers/ scripts which no longer crash: * recursive_call.py: fixed by gh-89419 * mutation_inside_cyclegc.py: fixed by gh-97922 * trace_at_recursion_limit.py: fixed by Python 3.7 --- Lib/test/crashers/mutation_inside_cyclegc.py | 31 ------------------- Lib/test/crashers/recursive_call.py | 15 --------- Lib/test/crashers/trace_at_recursion_limit.py | 27 ---------------- Lib/test/{crashers => test_crashers}/README | 8 ++--- .../__init__.py} | 30 +++++++++++------- .../bogus_code_obj.py | 9 ++++-- .../gc_inspection.py | 4 +++ .../infinite_loop_re.py | 0 .../underlying_dict.py | 0 Makefile.pre.in | 2 +- 10 files changed, 33 insertions(+), 93 deletions(-) delete mode 100644 Lib/test/crashers/mutation_inside_cyclegc.py delete mode 100755 Lib/test/crashers/recursive_call.py delete mode 100644 Lib/test/crashers/trace_at_recursion_limit.py rename Lib/test/{crashers => test_crashers}/README (75%) rename Lib/test/{test_crashers.py => test_crashers/__init__.py} (56%) rename Lib/test/{crashers => test_crashers}/bogus_code_obj.py (80%) rename Lib/test/{crashers => test_crashers}/gc_inspection.py (88%) rename Lib/test/{crashers => test_crashers}/infinite_loop_re.py (100%) rename Lib/test/{crashers => test_crashers}/underlying_dict.py (100%) diff --git a/Lib/test/crashers/mutation_inside_cyclegc.py b/Lib/test/crashers/mutation_inside_cyclegc.py deleted file mode 100644 index 2b67398bccce23a..000000000000000 --- 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/recursive_call.py b/Lib/test/crashers/recursive_call.py deleted file mode 100755 index 2d160a7de5dac71..000000000000000 --- a/Lib/test/crashers/recursive_call.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python3 - -# No bug report AFAIK, mail on python-dev on 2006-01-10 - -# This is a "won't fix" case. It is known that setting a high enough -# recursion limit crashes by overflowing the stack. Unless this is -# redesigned somehow, it won't go away. - -import sys - -sys.setrecursionlimit(1 << 30) -f = lambda f:f(f) - -if __name__ == '__main__': - f(f) 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 acd863f5509c49b..000000000000000 --- 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/crashers/README b/Lib/test/test_crashers/README similarity index 75% rename from Lib/test/crashers/README rename to Lib/test/test_crashers/README index 0259a0688cbc67c..19f67b7ea2c94e2 100644 --- a/Lib/test/crashers/README +++ b/Lib/test/test_crashers/README @@ -5,7 +5,7 @@ too obscure to invest the effort. Each test should fail when run from the command line: - ./python Lib/test/crashers/weakref_in_del.py + ./python Lib/test/test_crashers/bogus_code_obj.py Put as much info into a docstring or comments to help determine the cause of the failure, as well as a bugs.python.org issue number if it exists. Particularly @@ -15,6 +15,6 @@ Once the crash is fixed, the test case should be moved into an appropriate test (even if it was originally from the test suite). This ensures the regression doesn't happen again. And if it does, it should be easier to track down. -Also see Lib/test_crashers.py which exercises the crashers in this directory. -In particular, make sure to add any new infinite loop crashers to the black -list so it doesn't try to run them. +Also see Lib/test/test_crashers/__init__.py which exercises the crashers in +this directory. In particular, make sure to add any new infinite loop crashers +to the black list so it doesn't try to run them. diff --git a/Lib/test/test_crashers.py b/Lib/test/test_crashers/__init__.py similarity index 56% rename from Lib/test/test_crashers.py rename to Lib/test/test_crashers/__init__.py index 31b712028f8a127..44c4e94673fbb05 100644 --- a/Lib/test/test_crashers.py +++ b/Lib/test/test_crashers/__init__.py @@ -4,34 +4,40 @@ # If a crasher is fixed, it should be moved elsewhere in the test suite to # ensure it continues to work correctly. -import unittest import glob import os.path -import test.support +import unittest +from test import support from test.support.script_helper import assert_python_failure -CRASHER_DIR = os.path.join(os.path.dirname(__file__), "crashers") + +CRASHER_DIR = os.path.abspath(os.path.dirname(__file__)) CRASHER_FILES = os.path.join(glob.escape(CRASHER_DIR), "*.py") +infinite_loops = frozenset(["infinite_loop_re.py"]) -infinite_loops = ["infinite_loop_re.py", "nasty_eq_vs_dict.py"] class CrasherTest(unittest.TestCase): - - @unittest.skip("these tests are too fragile") - @test.support.cpython_only + @support.cpython_only def test_crashers_crash(self): + if support.verbose: + print() for fname in glob.glob(CRASHER_FILES): - if os.path.basename(fname) in infinite_loops: + script = os.path.basename(fname) + if script == "__init__.py": + continue + if script in infinite_loops: continue # Some "crashers" only trigger an exception rather than a # segfault. Consider that an acceptable outcome. - if test.support.verbose: - print("Checking crasher:", fname) - assert_python_failure(fname) + if support.verbose: + print(f"Checking crasher: {script}", flush=True) + proc = assert_python_failure(fname) + self.assertLess(proc.rc, 0, proc) def tearDownModule(): - test.support.reap_children() + support.reap_children() + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/crashers/bogus_code_obj.py b/Lib/test/test_crashers/bogus_code_obj.py similarity index 80% rename from Lib/test/crashers/bogus_code_obj.py rename to Lib/test/test_crashers/bogus_code_obj.py index e71b3582cf2d761..522b2bc3fecb1cd 100644 --- a/Lib/test/crashers/bogus_code_obj.py +++ b/Lib/test/test_crashers/bogus_code_obj.py @@ -14,6 +14,9 @@ import types -co = types.CodeType(0, 0, 0, 0, 0, 0, b'\x04\x00\x71\x00', - (), (), (), '', '', 1, b'') -exec(co) +def func(): + pass + +invalid_code = b'\x04\x00\x71\x00' +func.__code__ = func.__code__.replace(co_code=invalid_code) +func() diff --git a/Lib/test/crashers/gc_inspection.py b/Lib/test/test_crashers/gc_inspection.py similarity index 88% rename from Lib/test/crashers/gc_inspection.py rename to Lib/test/test_crashers/gc_inspection.py index ae85f97a74adc93..065109a31c0a278 100644 --- a/Lib/test/crashers/gc_inspection.py +++ b/Lib/test/test_crashers/gc_inspection.py @@ -15,6 +15,10 @@ fixes to the documentation for extension module writers. It's unlikely to happen, though. So this is currently classified as "gc.get_referrers() is dangerous, use only for debugging". + +* https://github.com/python/cpython/issues/39117 +* https://github.com/python/cpython/issues/59313 +* https://github.com/python/cpython/pull/107183 """ import gc diff --git a/Lib/test/crashers/infinite_loop_re.py b/Lib/test/test_crashers/infinite_loop_re.py similarity index 100% rename from Lib/test/crashers/infinite_loop_re.py rename to Lib/test/test_crashers/infinite_loop_re.py diff --git a/Lib/test/crashers/underlying_dict.py b/Lib/test/test_crashers/underlying_dict.py similarity index 100% rename from Lib/test/crashers/underlying_dict.py rename to Lib/test/test_crashers/underlying_dict.py diff --git a/Makefile.pre.in b/Makefile.pre.in index 9be5c3b50eb9ee2..59eab1894270095 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2144,7 +2144,6 @@ TESTSUBDIRS= idlelib/idle_test \ test/audiodata \ test/capath \ test/cjkencodings \ - test/crashers \ test/data \ test/decimaltestdata \ test/dtracedata \ @@ -2156,6 +2155,7 @@ TESTSUBDIRS= idlelib/idle_test \ test/support/_hypothesis_stubs \ test/test_asyncio \ test/test_capi \ + test/test_crashers \ test/test_ctypes \ test/test_email \ test/test_email/data \