From 8b19275a4d1c18447741db26df06eb7cb484e565 Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Fri, 14 Nov 2025 00:02:48 +0100 Subject: [PATCH 1/2] Fix a crash when running test_capi *after* test_code in the same process. --- Lib/test/test_code.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index 655f5a9be7fa31..6e21cb49f4c8f7 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -1555,6 +1555,13 @@ def myfree(ptr): FREE_FUNC = freefunc(myfree) FREE_INDEX = RequestCodeExtraIndex(FREE_FUNC) + # Make sure myfree sticks around at least as long as the interpreter, + # since we (currently) can't unregister the function and leaving a + # dangling pointer will cause a crash on deallocation of code objects if + # something else uses co_extras, like test_capi.test_misc. (Maybe this + # should use PyInterpreterState_GetDict, but that isn't easily exposed + # to Python code.) + setattr(sys, f'_test_code.{myfree!r}', myfree) class CoExtra(unittest.TestCase): def get_func(self): From 60e0a08ecc315b8a3a0a877a02e85062f6039e53 Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Tue, 18 Nov 2025 19:49:56 +0100 Subject: [PATCH 2/2] Use test.support.late_deletion instead of a sys attribute to keep the function alive. --- Lib/test/test_code.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index 6e21cb49f4c8f7..0d5c6e6e77f5d7 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -210,7 +210,7 @@ ctypes = None from test.support import (cpython_only, check_impl_detail, requires_debug_ranges, - gc_collect, Py_GIL_DISABLED) + gc_collect, Py_GIL_DISABLED, late_deletion) from test.support.script_helper import assert_python_ok from test.support import threading_helper, import_helper from test.support.bytecode_helper import instructions_with_positions @@ -1558,10 +1558,8 @@ def myfree(ptr): # Make sure myfree sticks around at least as long as the interpreter, # since we (currently) can't unregister the function and leaving a # dangling pointer will cause a crash on deallocation of code objects if - # something else uses co_extras, like test_capi.test_misc. (Maybe this - # should use PyInterpreterState_GetDict, but that isn't easily exposed - # to Python code.) - setattr(sys, f'_test_code.{myfree!r}', myfree) + # something else uses co_extras, like test_capi.test_misc. + late_deletion(myfree) class CoExtra(unittest.TestCase): def get_func(self):