GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Free-threading: data race on static cache in `_datetime.normalize_century()` · Issue #159458 · python/cpython

Free-threading: data race on static cache in _datetime.normalize_century() #159458

New issue
Copy link
New issue
Copy link
Closed
Closed
Free-threading: data race on static cache in _datetime.normalize_century()#159458
Copy link
Labels
extension-modulesC modules in the Modules dirC modules in the Modules dirtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@AnnaAr321
AnnaAr321
opened on Oct 15, 2026
Issue body actions

Bug report

Under free-threaded builds with ThreadSanitizer, concurrent calls to datetime.date.strftime(), datetime.datetime.strftime(), or time.strftime() with %Y, %G, %F, or %C format specifiers trigger a data race on the function-local static int cache = -1; variable in normalize_century() in Modules/_datetimemodule.c.

Reproducer

Note: Because cache is only written on the first call when cache < 0, the race only triggers if strftime() has not already been called on the main thread earlier in the process.

import datetime
import threading
d = datetime.date(2026, 4, 12)
num_threads = 8
barrier = threading.Barrier(num_threads)
def worker():
    barrier.wait()
    d.strftime("%Y-%m-%d")
threads = [threading.Thread(target=worker) for _ in range(num_threads)]
for t in threads:
    t.start()
for t in threads:
    t.join()

ThreadSanitizer output

WARNING: ThreadSanitizer: data race (pid=9244)
  Read of size 4 at 0x7fdd2ad2ee60 by thread T40:
    #0 normalize_century Modules/_datetimemodule.c:1762:9 
    #1 wrap_strftime Modules/_datetimemodule.c:1946:18 
    #2 date_strftime Modules/_datetimemodule.c:3592:14 
    #3 method_vectorcall_VARARGS_KEYWORDS Objects/descrobject.c:359:14 
    #4 _PyObject_VectorcallTstate Include/internal/pycore_call.h:177:11 
    #5 PyObject_Vectorcall Objects/call.c:327:12 
    #6 _PyEval_EvalFrameDefault Python/generated_cases.c.h:1621:35 
    #7 _PyEval_EvalFrame Include/internal/pycore_ceval.h:120:16 
    #8 _PyEval_Vector Python/ceval.c:2121:12 
    #9 _PyFunction_Vectorcall Objects/call.c 
    #10 _PyObject_VectorcallTstate Include/internal/pycore_call.h:177:11 
    #11 _PyObject_VectorcallPrepend Objects/call.c:852:20 
    #12 method_vectorcall Objects/classobject.c:54:12 
    #13 _PyObject_VectorcallTstate Include/internal/pycore_call.h:177:11 
    #14 context_run Python/context.c:722:29 
    #15 _PyEval_EvalFrameDefault Python/generated_cases.c.h:3762:35 
    #16 _PyEval_EvalFrame Include/internal/pycore_ceval.h:120:16 
    #17 _PyEval_Vector Python/ceval.c:2121:12 
    #18 _PyFunction_Vectorcall Objects/call.c 
    #19 _PyObject_VectorcallTstate Include/internal/pycore_call.h:177:11 
    #20 _PyObject_VectorcallPrepend Objects/call.c:852:20 
    #21 method_vectorcall Objects/classobject.c:54:12 
    #22 _PyVectorcall_Call Objects/call.c:273:16 
    #23 _PyObject_Call Objects/call.c:348:16 
    #24 PyObject_Call Objects/call.c:373:12 
    #25 thread_run Modules/_threadmodule.c:359:21 
    #26 pythread_wrapper Python/thread_pthread.h:242:5 

  Previous write of size 4 at 0x7fdd2ad2ee60 by thread T39:
    #0 normalize_century Modules/_datetimemodule.c:1769:15 
    #1 wrap_strftime Modules/_datetimemodule.c:1946:18 
    #2 date_strftime Modules/_datetimemodule.c:3592:14 
    #3 method_vectorcall_VARARGS_KEYWORDS Objects/descrobject.c:359:14 
    #4 _PyObject_VectorcallTstate Include/internal/pycore_call.h:177:11 
    #5 PyObject_Vectorcall Objects/call.c:327:12 
    #6 _PyEval_EvalFrameDefault Python/generated_cases.c.h:1621:35 
    #7 _PyEval_EvalFrame Include/internal/pycore_ceval.h:120:16 
    #8 _PyEval_Vector Python/ceval.c:2121:12 
    #9 _PyFunction_Vectorcall Objects/call.c 
    #10 _PyObject_VectorcallTstate Include/internal/pycore_call.h:177:11 
    #11 _PyObject_VectorcallPrepend Objects/call.c:852:20 
    #12 method_vectorcall Objects/classobject.c:54:12 
    #13 _PyObject_VectorcallTstate Include/internal/pycore_call.h:177:11 
    #14 context_run Python/context.c:722:29 
    #15 _PyEval_EvalFrameDefault Python/generated_cases.c.h:3762:35 
    #16 _PyEval_EvalFrame Include/internal/pycore_ceval.h:120:16 
    #17 _PyEval_Vector Python/ceval.c:2121:12 
    #18 _PyFunction_Vectorcall Objects/call.c 
    #19 _PyObject_VectorcallTstate Include/internal/pycore_call.h:177:11 
    #20 _PyObject_VectorcallPrepend Objects/call.c:852:20 
    #21 method_vectorcall Objects/classobject.c:54:12 
    #22 _PyVectorcall_Call Objects/call.c:273:16 
    #23 _PyObject_Call Objects/call.c:348:16 
    #24 PyObject_Call Objects/call.c:373:12 
    #25 thread_run Modules/_threadmodule.c:359:21 
    #26 pythread_wrapper Python/thread_pthread.h:242:5 

  Location is global 'normalize_century.cache' of size 4 at 0x7fdd2ad2ee60 (libpython3.14.so+0x41fe60)

  Thread T40 'Thread-40 (work' (tid=9289, running) created by main thread at:
    #0 pthread_create tsan_interceptors_posix.cpp:1083:3 
    #1 do_start_joinable_thread Python/thread_pthread.h:289:14 
    #2 PyThread_start_joinable_thread Python/thread_pthread.h:331:9 
    #3 ThreadHandle_start Modules/_threadmodule.c:445:9 
    #4 do_start_new_thread Modules/_threadmodule.c:1868:9
    #5 thread_PyThread_start_joinable_thread Modules/_threadmodule.c:1991:14 
    #6 cfunction_call Objects/methodobject.c:564:18 
    #7 _PyObject_MakeTpCall Objects/call.c:242:18 
    #8 _PyObject_VectorcallTstate Include/internal/pycore_call.h:175:16 
    #9 PyObject_Vectorcall Objects/call.c:327:12 
    #10 _PyEval_EvalFrameDefault Python/generated_cases.c.h:3241:35 
    #11 _PyEval_EvalFrame Include/internal/pycore_ceval.h:120:16 
    #12 _PyEval_Vector Python/ceval.c:2121:12 
    #13 _PyFunction_Vectorcall Objects/call.c 
    #14 _PyObject_VectorcallTstate Include/internal/pycore_call.h:177:11 
    #15 _PyObject_VectorcallPrepend Objects/call.c:874:18 
    #16 method_vectorcall Objects/classobject.c:54:12 
    #17 _PyVectorcall_Call Objects/call.c:273:16 
    #18 _PyObject_Call Objects/call.c:348:16 
    #19 PyObject_Call Objects/call.c:373:12 
    #20 _PyEval_EvalFrameDefault Python/generated_cases.c.h:2666:32 
    #21 _PyEval_EvalFrame Include/internal/pycore_ceval.h:120:16 
    #22 _PyEval_Vector Python/ceval.c:2121:12 
    #23 _PyFunction_Vectorcall Objects/call.c 
    #24 _PyObject_VectorcallDictTstate Objects/call.c:135:15 
    #25 _PyObject_Call_Prepend Objects/call.c:504:24 
    #26 call_method Objects/typeobject.c:3080:19 
    #27 slot_tp_call Objects/typeobject.c:10590:12 
    #28 _PyObject_MakeTpCall Objects/call.c:242:18 
    #29 _PyObject_VectorcallTstate Include/internal/pycore_call.h:175:16 
    #30 PyObject_Vectorcall Objects/call.c:327:12 
    #31 _PyEval_EvalFrameDefault Python/generated_cases.c.h:4103:35 
    #32 _PyEval_EvalFrame Include/internal/pycore_ceval.h:120:16 
    #33 _PyEval_Vector Python/ceval.c:2121:12 
    #34 _PyFunction_Vectorcall Objects/call.c 
    #35 _PyObject_VectorcallTstate Include/internal/pycore_call.h:177:11 
    #36 _PyObject_VectorcallPrepend Objects/call.c:874:18 
    #37 method_vectorcall Objects/classobject.c:54:12 
    #38 _PyVectorcall_Call Objects/call.c:273:16 
    #39 _PyObject_Call Objects/call.c:348:16 
    #40 PyObject_Call Objects/call.c:373:12 
    #41 _PyEval_EvalFrameDefault Python/generated_cases.c.h:2666:32 
    #42 _PyEval_EvalFrame Include/internal/pycore_ceval.h:120:16 
    #43 _PyEval_Vector Python/ceval.c:2121:12 
    #44 _PyFunction_Vectorcall Objects/call.c 
    #45 _PyObject_VectorcallDictTstate Objects/call.c:135:15 
    #46 _PyObject_Call_Prepend Objects/call.c:504:24 
    #47 call_method Objects/typeobject.c:3080:19 
    #48 slot_tp_call Objects/typeobject.c:10590:12 
    #49 _PyObject_MakeTpCall Objects/call.c:242:18 
    #50 _PyObject_VectorcallTstate Include/internal/pycore_call.h:175:16 
    #51 PyObject_Vectorcall Objects/call.c:327:12 
    #52 _PyEval_EvalFrameDefault Python/generated_cases.c.h:1621:35 
    #53 _PyEval_EvalFrame Include/internal/pycore_ceval.h:120:16 
    #54 _PyEval_Vector Python/ceval.c:2121:12 
    #55 PyEval_EvalCode Python/ceval.c:992:21 
    #56 builtin_exec_impl Python/bltinmodule.c:1180:17 
    #57 builtin_exec Python/clinic/bltinmodule.c.h:571:20 
    #58 cfunction_vectorcall_FASTCALL_KEYWORDS Objects/methodobject.c:465:24 
    #59 _PyObject_VectorcallTstate Include/internal/pycore_call.h:177:11 
    #60 PyObject_Vectorcall Objects/call.c:327:12 
    #61 _PyEval_EvalFrameDefault Python/generated_cases.c.h:1621:35 
    #62 _PyEval_EvalFrame Include/internal/pycore_ceval.h:120:16 
    #63 _PyEval_Vector Python/ceval.c:2121:12 
    #64 _PyFunction_Vectorcall Objects/call.c 
    #65 _PyObject_VectorcallTstate Include/internal/pycore_call.h:177:11 
    #66 _PyObject_CallFunctionVa Objects/call.c 
    #67 callmethod Objects/call.c:626:12 
    #68 PyObject_CallMethod Objects/call.c:645:24 
    #69 RunFileAsMain launcher_common.cc:147:12 
    #70 RunMainFromImporter launcher_common.cc:523:11 
    #71 Launcher_Main launcher_common.cc:790:14 
    #72 HermeticLauncherMain hermetic_launcher_lib.cc:113:10 
    #73 main hermetic_launcher.cc:4:10 

  Thread T39 'Thread-39 (work' (tid=9288, running) created by main thread at:
    #0 pthread_create tsan_interceptors_posix.cpp:1083:3 
    #1 do_start_joinable_thread Python/thread_pthread.h:289:14 
    #2 PyThread_start_joinable_thread Python/thread_pthread.h:331:9 
    #3 ThreadHandle_start Modules/_threadmodule.c:445:9 
    #4 do_start_new_thread Modules/_threadmodule.c:1868:9
    #5 thread_PyThread_start_joinable_thread Modules/_threadmodule.c:1991:14 
    #6 cfunction_call Objects/methodobject.c:564:18 
    #7 _PyObject_MakeTpCall Objects/call.c:242:18 
    #8 _PyObject_VectorcallTstate Include/internal/pycore_call.h:175:16 
    #9 PyObject_Vectorcall Objects/call.c:327:12 
    #10 _PyEval_EvalFrameDefault Python/generated_cases.c.h:3241:35 
    #11 _PyEval_EvalFrame Include/internal/pycore_ceval.h:120:16 
    #12 _PyEval_Vector Python/ceval.c:2121:12 
    #13 _PyFunction_Vectorcall Objects/call.c 
    #14 _PyObject_VectorcallTstate Include/internal/pycore_call.h:177:11 
    #15 _PyObject_VectorcallPrepend Objects/call.c:874:18 
    #16 method_vectorcall Objects/classobject.c:54:12 
    #17 _PyVectorcall_Call Objects/call.c:273:16 

SUMMARY: ThreadSanitizer: data race Modules/_datetimemodule.c in normalize_century

CPython versions tested on:

3.14, free-threaded build

CPython versions tested on:

3.14

Operating systems tested on:

Linux

Linked PRs

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

Activity

  1. AnnaAr321
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on Oct 15, 2026
  2. AnnaAr321 commented on Oct 15, 2026

    @AnnaAr321
    AnnaAr321
    on Oct 15, 2026
    ContributorAuthor
    More actions

    I have prepared a fix for it and will mail it promptly

    Reacted by Petr Viktorin and Srinivas Reddy Thatiparthy (తాటిపర్తి శ్రీనివాస్ రెడ్డి)
  3. encukou
    added
    stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
    on Oct 15, 2026
  4. encukou commented on Oct 15, 2026

    @encukou
    encukou
    on Oct 15, 2026
    Member
    More actions

    I have prepared a fix for it and will mail it promptly

    Thank you; please do!

  5. StanFromIreland
    added this to Date and time issues 🕰️on Oct 15, 2026
  6. StanFromIreland
    added
    extension-modulesC modules in the Modules dirC modules in the Modules dir
    and removed
    stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
    on Oct 15, 2026
  7. encukou
    added a commit that references this issue on Oct 16, 2026

    gh-159458: Fix free-threading data race in datetime strftime century …

    ddc647a
  8. kevinprimeraquecreo-stack
    added this to Project_VKand Project_VKon Oct 18, 2026
  9. github-project-automation
    moved this to Todo in Project_VKon Oct 18, 2026
  10. corona10
    added 2 commits that reference this issue on Oct 20, 2026

    [3.15] gh-159458: Fix free-threading data race in datetime strftime c…

    d89f40b

    [3.14] gh-159458: Fix free-threading data race in datetime strftime c…

    9d6f05e
  11. corona10
    closed this as completedon Oct 20, 2026
  12. github-project-automation
    moved this to Done in Date and time issues 🕰️on Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    extension-modulesC modules in the Modules dirC modules in the Modules dirtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

    Projects

    • Date and time issues 🕰️
      Status
      Done
      Show more project fields

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    You are visitor 01402503 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.