From bb256a082888be10385850ba72affdfe7c6732d4 Mon Sep 17 00:00:00 2001 From: Anna Date: Fri, 16 Oct 2026 12:21:03 +0200 Subject: [PATCH 1/2] Fix free-threading data race in datetime strftime century normalization --- Lib/test/test_free_threading/test_datetime.py | 25 +++++++++++++++++++ Modules/_datetimemodule.c | 10 +++++--- 2 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 Lib/test/test_free_threading/test_datetime.py 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/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index bd76b3bd81cce4..dbd14f1d707077 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 * From 5b5744762d886ce5c2e0937195a0efc4bb99e397 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Fri, 16 Oct 2026 10:25:24 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2026-10-16-10-25-22.gh-issue-159458.q02EnY.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2026-10-16-10-25-22.gh-issue-159458.q02EnY.rst 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.