From 611cb81b6622a8927058a060f32b2bc014d37867 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 17 Sep 2026 16:34:50 +0200 Subject: [PATCH] gh-157415: Fix data race in pthread wrapper (#157430) Use free() instead of PyMem_RawFree() in pythread_wrapper() to avoid a data race if another thread calls PyMem_SetAllocator() in parallel. Reenable @nomemtest tests on TSAN. Co-authored-by: Nathan Goldbaum (cherry picked from commit d1878ccb44999bfa30f5a0e84b4383e6068e5b72) --- Lib/test/support/__init__.py | 7 +------ Python/thread_pthread.h | 8 +++++--- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 5a142ac4adca56..ef04637a49197b 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1314,12 +1314,7 @@ def internal(*args, **kwargs): import_module('_testcapi') return f(*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/Python/thread_pthread.h b/Python/thread_pthread.h index de93178576e6ec..4972a2a6b36c9b 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -229,7 +229,7 @@ pythread_wrapper(void *arg) pythread_callback *callback = arg; void (*func)(void *) = callback->func; void *func_arg = callback->arg; - PyMem_RawFree(arg); + free(callback); func(func_arg); return NULL; @@ -269,7 +269,9 @@ do_start_joinable_thread(void (*func)(void *), void *arg, pthread_t* out_id) pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM); #endif - pythread_callback *callback = PyMem_RawMalloc(sizeof(pythread_callback)); + // Use free() instead of PyMem_RawFree() in pythread_wrapper() to avoid a + // data race if another thread calls PyMem_SetAllocator() in parallel. + pythread_callback *callback = malloc(sizeof(pythread_callback)); if (callback == NULL) { return -1; @@ -291,7 +293,7 @@ do_start_joinable_thread(void (*func)(void *), void *arg, pthread_t* out_id) #endif if (status != 0) { - PyMem_RawFree(callback); + free(callback); return -1; } *out_id = th;