]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.15] gh-153292: Fix data race in `threading.RLock.__repr__` in FT builds (GH-153299...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Wed, 8 Jul 2026 10:13:44 +0000 (12:13 +0200)
committerGitHub <noreply@github.com>
Wed, 8 Jul 2026 10:13:44 +0000 (10:13 +0000)
gh-153292: Fix data race in `threading.RLock.__repr__` in FT builds (GH-153299)
(cherry picked from commit 1051384fcdfa88dd88d66dfc93b60aec9ca1ad2e)

Co-authored-by: sobolevn <mail@sobolevn.me>
Lib/test/test_free_threading/test_threading.py [new file with mode: 0644]
Misc/NEWS.d/next/Library/2026-07-08-01-03-17.gh-issue-153292.oHDt3l.rst [new file with mode: 0644]
Modules/_threadmodule.c

diff --git a/Lib/test/test_free_threading/test_threading.py b/Lib/test/test_free_threading/test_threading.py
new file mode 100644 (file)
index 0000000..b5a5ca2
--- /dev/null
@@ -0,0 +1,26 @@
+import unittest
+from test.support import threading_helper
+
+threading_helper.requires_working_threading(module=True)
+
+
+class TestRlock(unittest.TestCase):
+    def test_repr_race(self):
+        # gh-153292
+        import _thread
+        r = _thread.RLock()
+
+        def repr_thread():
+            for _ in range(2000):
+                repr(r)
+
+        def mutate_thread():
+            for _ in range(2000):
+                r.acquire()
+                r.release()
+
+        threading_helper.run_concurrently([repr_thread, mutate_thread])
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/Misc/NEWS.d/next/Library/2026-07-08-01-03-17.gh-issue-153292.oHDt3l.rst b/Misc/NEWS.d/next/Library/2026-07-08-01-03-17.gh-issue-153292.oHDt3l.rst
new file mode 100644 (file)
index 0000000..dc363e1
--- /dev/null
@@ -0,0 +1 @@
+Fix data race in repr of :class:`threading.RLock` in free-threading build.
index 7e1884edf5213e360dce3296347b02fc310b430c..e999fe20287e2d6ef6d08cc94100cab06ca9b4b1 100644 (file)
@@ -1288,7 +1288,7 @@ static PyObject *
 rlock_repr(PyObject *op)
 {
     rlockobject *self = rlockobject_CAST(op);
-    PyThread_ident_t owner = self->lock.thread;
+    PyThread_ident_t owner = FT_ATOMIC_LOAD_ULLONG_RELAXED(self->lock.thread);
     int locked = rlock_locked_impl(self);
     size_t count;
     if (locked) {