Skip to content

Commit ddc647a

Browse files
authored
gh-159458: Fix free-threading data race in datetime strftime century normalization (GH-159520)
1 parent c7a1716 commit ddc647a

3 files changed

Lines changed: 32 additions & 4 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import datetime
2+
import unittest
3+
4+
from test.support import threading_helper
5+
from test.support.threading_helper import run_concurrently
6+
7+
8+
NTHREADS = 10
9+
10+
11+
@threading_helper.requires_working_threading()
12+
class TestDatetime(unittest.TestCase):
13+
def test_concurrent_strftime_normalize_century(self):
14+
d = datetime.date(2026, 4, 12)
15+
results = []
16+
17+
def worker():
18+
results.append(d.strftime("%Y-%m-%d"))
19+
20+
run_concurrently(worker_func=worker, nthreads=NTHREADS)
21+
self.assertEqual(results, ["2026-04-12"] * NTHREADS)
22+
23+
24+
if __name__ == "__main__":
25+
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix a ThreadSanitizer data race on the static cache in ``normalize_century()`` of the datetime module under the free-threaded build.

‎Modules/_datetimemodule.c‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,17 +1783,19 @@ inline static int
17831783
normalize_century(void)
17841784
{
17851785
static int cache = -1;
1786-
if (cache < 0) {
1786+
int res = FT_ATOMIC_LOAD_INT_RELAXED(cache);
1787+
if (res < 0) {
17871788
char year[5];
17881789
struct tm date = {
17891790
.tm_year = -1801,
17901791
.tm_mon = 0,
17911792
.tm_mday = 1
17921793
};
1793-
cache = (strftime(year, sizeof(year), "%Y", &date) &&
1794-
strcmp(year, "0099") != 0);
1794+
res = (strftime(year, sizeof(year), "%Y", &date) &&
1795+
strcmp(year, "0099") != 0);
1796+
FT_ATOMIC_STORE_INT_RELAXED(cache, res);
17951797
}
1796-
return cache;
1798+
return res;
17971799
}
17981800

17991801
static PyObject *

0 commit comments

Comments
 (0)