https://github.com/python/cpython/commit/d1878ccb44999bfa30f5a0e84b4383e6068e5b72
commit: d1878ccb44999bfa30f5a0e84b4383e6068e5b72
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2026-09-17T16:34:50+02:00
summary:

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 <[email protected]>

files:
M Lib/test/support/__init__.py
M Python/thread_pthread.h

diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 13c7cec64dcf578..21ff5df44aad373 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -1373,11 +1373,7 @@ def internal(*args, **kwargs):
         import_module('_testcapi')
         return test(*args, **kwargs)
 
-    use_tsan = check_sanitizer(thread=True)
-    reason ='not working with thread sanitizer (gh-157415)'
-    skip_if_tsan = unittest.skipIf(use_tsan, reason)
-
-    return cpython_only(skip_if_tsan(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 8d727326faeb70d..e660bca84068604 100644
--- a/Python/thread_pthread.h
+++ b/Python/thread_pthread.h
@@ -231,7 +231,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;
@@ -271,7 +271,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;
@@ -293,7 +295,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;

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to