https://github.com/python/cpython/commit/ddc647a3410f05e99b2c65d40283e4ad6d903bef
commit: ddc647a3410f05e99b2c65d40283e4ad6d903bef
branch: main
author: Anna <[email protected]>
committer: encukou <[email protected]>
date: 2026-10-16T16:16:09+02:00
summary:
gh-159458: Fix free-threading data race in datetime strftime century
normalization (GH-159520)
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 000000000000000..6cea76b32d9ffcc
--- /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 000000000000000..6565f4265b5877c
--- /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 bd76b3bd81cce40..dbd14f1d7070772 100644
--- a/Modules/_datetimemodule.c
+++ b/Modules/_datetimemodule.c
@@ -1783,17 +1783,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]