From 640277e21d1968b2ec8c39a72bf88d1538a7ae7a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 12 Sep 2026 05:27:05 +0200 Subject: [PATCH] gh-157242: Fix set_nomemory() on Py_TRACE_REFS build (#157351) On Py_TRACE_REFS build, use malloc() and free() functions of the C library for the "reference chain" hash table. So it becomes possible to use _testcapi.set_nomemory() with Py_TRACE_REFS. Mark new tests using set_nomemory() with @support.nomemtest. (cherry picked from commit 051b168e63af80872222a2d91d43af4de16980b1) --- Lib/test/support/__init__.py | 13 ++++--------- Objects/object.c | 9 +++++---- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 8764d66514c4b3b..dc6204d0a84658b 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1217,21 +1217,16 @@ def wrapper(self): return wrapper return decorator -def nomemtest(f): +def nomemtest(test): """Check that we can use this test with `_testcapi.set_nomemory`.""" from .import_helper import import_module - @functools.wraps(f) + @functools.wraps(test) def internal(*args, **kwargs): import_module('_testcapi') - return f(*args, **kwargs) + return test(*args, **kwargs) - return unittest.skipIf( - # Python built with Py_TRACE_REFS fail with a fatal error in - # _PyRefchain_Trace() on memory allocation error. - Py_TRACE_REFS, - 'cannot test Py_TRACE_REFS build', - )(cpython_only(internal)) + return cpython_only(internal) def bigaddrspacetest(f): """Decorator for tests that fill the address space.""" diff --git a/Objects/object.c b/Objects/object.c index b17a5bd70caf91d..b0bfaf0a5c4195b 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -196,10 +196,11 @@ refchain_init(PyInterpreterState *interp) return 0; } _Py_hashtable_allocator_t alloc = { - // Don't use default PyMem_Malloc() and PyMem_Free() which - // require the caller to hold the GIL. - .malloc = PyMem_RawMalloc, - .free = PyMem_RawFree, + // Use directly malloc() and free() of the C library. Using + // PyMem_RawMalloc() and PyMem_RawFree() prevents testing + // _testcapi.set_nomemory(). + .malloc = malloc, + .free = free, }; REFCHAIN(interp) = _Py_hashtable_new_full( _Py_hashtable_hash_ptr, _Py_hashtable_compare_direct,