https://github.com/python/cpython/commit/d89f40b4c410960869dec020b2974e102e82689d
commit: d89f40b4c410960869dec020b2974e102e82689d
branch: 3.15
author: Miss Islington (bot) <[email protected]>
committer: corona10 <[email protected]>
date: 2026-10-20T11:57:32-07:00
summary:

[3.15] gh-159458: Fix free-threading data race in datetime strftime century 
normalization (GH-159520) (gh-159536)

gh-159458: Fix free-threading data race in datetime strftime century 
normalization (GH-159520)
(cherry picked from commit ddc647a3410f05e99b2c65d40283e4ad6d903bef)

Co-authored-by: Anna <[email protected]>

files:
A Lib/test/test_free_threading/test_datetime.py
A Misc/NEWS.d/next/Library/2026-10-16-10-25-22.gh-issue-159458.q02EnY.rst
M Modules/_datetimemodule.c

diff --git a/Lib/test/test_free_threading/test_datetime.py 
b/Lib/test/test_free_threading/test_datetime.py
new file mode 100644
index 00000000000000..6cea76b32d9ffc
--- /dev/null
+++ b/Lib/test/test_free_threading/test_datetime.py
@@ -0,0 +1,25 @@
+import datetime
+import unittest
+
+from test.support import threading_helper
+from test.support.threading_helper import run_concurrently
+
+
+NTHREADS = 10
+
+
+@threading_helper.requires_working_threading()
+class TestDatetime(unittest.TestCase):
+    def test_concurrent_strftime_normalize_century(self):
+        d = datetime.date(2026, 4, 12)
+        results = []
+
+        def worker():
+            results.append(d.strftime("%Y-%m-%d"))
+
+        run_concurrently(worker_func=worker, nthreads=NTHREADS)
+        self.assertEqual(results, ["2026-04-12"] * NTHREADS)
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git 
a/Misc/NEWS.d/next/Library/2026-10-16-10-25-22.gh-issue-159458.q02EnY.rst 
b/Misc/NEWS.d/next/Library/2026-10-16-10-25-22.gh-issue-159458.q02EnY.rst
new file mode 100644
index 00000000000000..6565f4265b5877
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-10-16-10-25-22.gh-issue-159458.q02EnY.rst
@@ -0,0 +1 @@
+Fix a ThreadSanitizer data race on the static cache in ``normalize_century()`` 
of the datetime module under the free-threaded build.
diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c
index d0f2e8c7dcabe4..fc07b4b7bc01fb 100644
--- a/Modules/_datetimemodule.c
+++ b/Modules/_datetimemodule.c
@@ -1780,17 +1780,19 @@ inline static int
 normalize_century(void)
 {
     static int cache = -1;
-    if (cache < 0) {
+    int res = FT_ATOMIC_LOAD_INT_RELAXED(cache);
+    if (res < 0) {
         char year[5];
         struct tm date = {
             .tm_year = -1801,
             .tm_mon = 0,
             .tm_mday = 1
         };
-        cache = (strftime(year, sizeof(year), "%Y", &date) &&
-                 strcmp(year, "0099") != 0);
+        res = (strftime(year, sizeof(year), "%Y", &date) &&
+               strcmp(year, "0099") != 0);
+        FT_ATOMIC_STORE_INT_RELAXED(cache, res);
     }
-    return cache;
+    return res;
 }
 
 static PyObject *

_______________________________________________
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