]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.14] gh-153298: Fix data race in `GenericAlias` parameter initialization on FT...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Wed, 8 Jul 2026 15:21:55 +0000 (17:21 +0200)
committerGitHub <noreply@github.com>
Wed, 8 Jul 2026 15:21:55 +0000 (15:21 +0000)
gh-153298: Fix data race in `GenericAlias` parameter initialization on FT (GH-153318)
(cherry picked from commit 68abf17fa926db94dc17f01a7095bdcee2a52314)

Co-authored-by: sobolevn <mail@sobolevn.me>
Lib/test/test_free_threading/test_types.py [new file with mode: 0644]
Misc/NEWS.d/next/Core_and_Builtins/2026-07-08-13-23-11.gh-issue-153298.wvcXxN.rst [new file with mode: 0644]
Objects/genericaliasobject.c

diff --git a/Lib/test/test_free_threading/test_types.py b/Lib/test/test_free_threading/test_types.py
new file mode 100644 (file)
index 0000000..76fcf15
--- /dev/null
@@ -0,0 +1,33 @@
+import unittest
+from typing import TypeVar
+from test.support import threading_helper
+
+threading_helper.requires_working_threading(module=True)
+
+
+class TestGenericAlias(unittest.TestCase):
+    def test_parameters_race(self):
+        # gh-153298
+
+        T = TypeVar('T')
+        slot = [list[T]]
+
+        def access():
+            for _ in range(2000):
+                try:
+                    _ = slot[0].__parameters__
+                except Exception:
+                    pass
+
+        def refresh():
+            for _ in range(2000):
+                slot[0] = list[T]
+
+        threading_helper.run_concurrently([
+            *[access for _ in range(6)],
+            *[refresh for _ in range(2)],
+        ])
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-08-13-23-11.gh-issue-153298.wvcXxN.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-08-13-23-11.gh-issue-153298.wvcXxN.rst
new file mode 100644 (file)
index 0000000..38d5488
--- /dev/null
@@ -0,0 +1,2 @@
+Fixes a data race in :class:`types.GenericAlias` ``__parameters__``
+initialization on free-threading builds.
index e6ee0b74e38f83692b9faa346a7d09745a63b20b..fb96fa9e9f65811f14df0ef38d7d193f7a36c61c 100644 (file)
@@ -838,7 +838,7 @@ static PyMemberDef ga_members[] = {
 };
 
 static PyObject *
-ga_parameters(PyObject *self, void *unused)
+ga_parameters_lock_held(PyObject *self)
 {
     gaobject *alias = (gaobject *)self;
     if (alias->parameters == NULL) {
@@ -850,6 +850,16 @@ ga_parameters(PyObject *self, void *unused)
     return Py_NewRef(alias->parameters);
 }
 
+static PyObject *
+ga_parameters(PyObject *self, void *unused)
+{
+    PyObject *result;
+    Py_BEGIN_CRITICAL_SECTION(self);
+    result = ga_parameters_lock_held(self);
+    Py_END_CRITICAL_SECTION();
+    return result;
+}
+
 static PyObject *
 ga_unpacked_tuple_args(PyObject *self, void *unused)
 {