Skip to content

data races in decimal module with global context #141148

Description

@kumaraditya303

Reproducer:

import decimal
from threading import Thread, Barrier

context = decimal.Context()
context.prec = 28

barrier = Barrier(10)

def race():
    barrier.wait()
    decimal.Decimal('1.0', context=context)

if __name__ == "__main__":
    while True:
        threads = [Thread(target=race) for _ in range(10)]
        for thread in threads:
            thread.start()
        for thread in threads:
            thread.join()

Data race:

==================
WARNING: ThreadSanitizer: data race (pid=58514)
  Write of size 4 at 0x00010d315cbc by thread T5808:
    #0 dec_addstatus _decimal.c:612 (_decimal.cpython-315t-darwin.so:arm64+0x9a88)
    #1 PyDecType_FromCStringExact _decimal.c:2323 (_decimal.cpython-315t-darwin.so:arm64+0x1a4a4)
    #2 dec_new _decimal.c.h:572 (_decimal.cpython-315t-darwin.so:arm64+0x506c)
    #3 type_call typeobject.c:2432 (python.exe:arm64+0x10017e768)
    #4 _PyObject_MakeTpCall call.c:242 (python.exe:arm64+0x10007eb64)
    #5 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x10007f750)
    #6 _PyEval_EvalFrameDefault generated_cases.c.h:1620 (python.exe:arm64+0x100277dec)
    #7 _PyEval_Vector ceval.c:1989 (python.exe:arm64+0x10026ad88)
    #8 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007fcec)
    #9 method_vectorcall classobject.c:65 (python.exe:arm64+0x100084190)
    #10 _PyObject_Call call.c:348 (python.exe:arm64+0x10007f8b0)
    #11 PyObject_Call call.c:373 (python.exe:arm64+0x10007f9d8)
    #12 _PyEval_EvalFrameDefault generated_cases.c.h:2616 (python.exe:arm64+0x10027bf64)
    #13 _PyEval_Vector ceval.c:1989 (python.exe:arm64+0x10026ad88)
    #14 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007fcec)
    #15 method_vectorcall classobject.c:73 (python.exe:arm64+0x10008422c)
    #16 context_run context.c:728 (python.exe:arm64+0x1002b53dc)
    #17 _PyEval_EvalFrameDefault generated_cases.c.h:3710 (python.exe:arm64+0x10027ffbc)
    #18 _PyEval_Vector ceval.c:1989 (python.exe:arm64+0x10026ad88)
    #19 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007fcec)
    #20 method_vectorcall classobject.c:73 (python.exe:arm64+0x10008422c)
    #21 _PyObject_Call call.c:348 (python.exe:arm64+0x10007f964)
    #22 PyObject_Call call.c:373 (python.exe:arm64+0x10007f9d8)
    #23 thread_run _threadmodule.c:387 (python.exe:arm64+0x10041b338)
    #24 pythread_wrapper thread_pthread.h:234 (python.exe:arm64+0x100358824)

  Previous write of size 4 at 0x00010d315cbc by thread T5806:
    #0 dec_addstatus _decimal.c:612 (_decimal.cpython-315t-darwin.so:arm64+0x9a88)
    #1 PyDecType_FromCStringExact _decimal.c:2323 (_decimal.cpython-315t-darwin.so:arm64+0x1a4a4)
    #2 dec_new _decimal.c.h:572 (_decimal.cpython-315t-darwin.so:arm64+0x506c)
    #3 type_call typeobject.c:2432 (python.exe:arm64+0x10017e768)
    #4 _PyObject_MakeTpCall call.c:242 (python.exe:arm64+0x10007eb64)
    #5 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x10007f750)
    #6 _PyEval_EvalFrameDefault generated_cases.c.h:1620 (python.exe:arm64+0x100277dec)
    #7 _PyEval_Vector ceval.c:1989 (python.exe:arm64+0x10026ad88)
    #8 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007fcec)
    #9 method_vectorcall classobject.c:65 (python.exe:arm64+0x100084190)
    #10 _PyObject_Call call.c:348 (python.exe:arm64+0x10007f8b0)
    #11 PyObject_Call call.c:373 (python.exe:arm64+0x10007f9d8)
    #12 _PyEval_EvalFrameDefault generated_cases.c.h:2616 (python.exe:arm64+0x10027bf64)
    #13 _PyEval_Vector ceval.c:1989 (python.exe:arm64+0x10026ad88)
    #14 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007fcec)
    #15 method_vectorcall classobject.c:73 (python.exe:arm64+0x10008422c)
    #16 context_run context.c:728 (python.exe:arm64+0x1002b53dc)
    #17 _PyEval_EvalFrameDefault generated_cases.c.h:3710 (python.exe:arm64+0x10027ffbc)
    #18 _PyEval_Vector ceval.c:1989 (python.exe:arm64+0x10026ad88)
    #19 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007fcec)
    #20 method_vectorcall classobject.c:73 (python.exe:arm64+0x10008422c)
    #21 _PyObject_Call call.c:348 (python.exe:arm64+0x10007f964)
    #22 PyObject_Call call.c:373 (python.exe:arm64+0x10007f9d8)
    #23 thread_run _threadmodule.c:387 (python.exe:arm64+0x10041b338)
    #24 pythread_wrapper thread_pthread.h:234 (python.exe:arm64+0x100358824)
SUMMARY: ThreadSanitizer: data race _decimal.c:615 in dec_addstatus
==================

I discovered this while adding thread safety support to msgspec. Running its test suite under pytest-run-parallel leads to similar data races as present above from the minimal reproducer.

See https://gist.github.com/kumaraditya303/3c26f31eaf0beea39d7eeb539b662846 for full tsan report

Linked PRs

Activity

  1. colesbury commented on Nov 21, 2025

    @colesbury
    Contributor

    I don't think you should be sharing contexts across threads.

    https://docs.python.org/3/library/decimal.html#context-objects

    "Each thread has its own current context which is accessed or changed using the getcontext() and setcontext() functions"

    I'm not sure if we should explicitly disallow it or leave things as is.

  2. colesbury commented on Nov 21, 2025

    @colesbury
    Contributor

    Hmm... actually, I guess things like decimal.BasicContext will always be shared across threads.

  3. skirpichev commented on Nov 21, 2025

    @skirpichev
    Member

    There is also section Working with threads. I don't think that OP example fits in this picture. (Though, maybe we should reclassify this as a documentation issue, instead of closing.)

    BTW, what was original test failure?

  4. kumaraditya303 commented on Nov 22, 2025

    @kumaraditya303
    ContributorAuthor

    Another reproducer which does not shares a global context:

    from decimal import Decimal
    import numpy as np
    
    def test_array_gcd_lcm_decimal():
        a = np.array([1,  1, -1, -1]) * Decimal('0.20')

    Running this under pytest-run-parallel leads to similar data races.

    Details
    ==================
    WARNING: ThreadSanitizer: data race (pid=10816)
      Write of size 4 at 0x00012305b23c by thread T1:
        #0 dec_addstatus <null> (_decimal.cpython-314t-darwin.so:arm64+0x98e4)
        #1 PyDecType_FromCStringExact <null> (_decimal.cpython-314t-darwin.so:arm64+0x197c8)
        #2 dec_new <null> (_decimal.cpython-314t-darwin.so:arm64+0x4e9c)
        #3 type_call <null> (libpython3.14t.dylib:arm64+0x18a600)
        #4 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #5 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #6 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27ce94)
        #7 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #8 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #9 method_vectorcall <null> (libpython3.14t.dylib:arm64+0x8f638)
        #10 context_run <null> (libpython3.14t.dylib:arm64+0x2c3eec)
        #11 method_vectorcall_FASTCALL_KEYWORDS <null> (libpython3.14t.dylib:arm64+0xa1c48)
        #12 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ab8c)
        #13 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27ce94)
        #14 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #15 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #16 method_vectorcall <null> (libpython3.14t.dylib:arm64+0x8f638)
        #17 _PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8ae40)
        #18 PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8aeb4)
        #19 thread_run <null> (libpython3.14t.dylib:arm64+0x416b08)
        #20 pythread_wrapper <null> (libpython3.14t.dylib:arm64+0x368cac)
    
      Previous write of size 4 at 0x00012305b23c by thread T4:
        #0 dec_addstatus <null> (_decimal.cpython-314t-darwin.so:arm64+0x98e4)
        #1 PyDecType_FromCStringExact <null> (_decimal.cpython-314t-darwin.so:arm64+0x197c8)
        #2 dec_new <null> (_decimal.cpython-314t-darwin.so:arm64+0x4e9c)
        #3 type_call <null> (libpython3.14t.dylib:arm64+0x18a600)
        #4 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #5 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #6 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27ce94)
        #7 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #8 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #9 method_vectorcall <null> (libpython3.14t.dylib:arm64+0x8f638)
        #10 context_run <null> (libpython3.14t.dylib:arm64+0x2c3eec)
        #11 method_vectorcall_FASTCALL_KEYWORDS <null> (libpython3.14t.dylib:arm64+0xa1c48)
        #12 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ab8c)
        #13 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27ce94)
        #14 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #15 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #16 method_vectorcall <null> (libpython3.14t.dylib:arm64+0x8f638)
        #17 _PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8ae40)
        #18 PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8aeb4)
        #19 thread_run <null> (libpython3.14t.dylib:arm64+0x416b08)
        #20 pythread_wrapper <null> (libpython3.14t.dylib:arm64+0x368cac)
    
      Thread T1 (tid=892055, running) created by main thread at:
        #0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x2f708)
        #1 do_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x36796c)
        #2 PyThread_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x3677b4)
        #3 do_start_new_thread <null> (libpython3.14t.dylib:arm64+0x4166bc)
        #4 thread_PyThread_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x415448)
        #5 cfunction_call <null> (libpython3.14t.dylib:arm64+0x12bfb4)
        #6 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #7 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #8 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #9 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #10 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #11 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #12 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #13 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #14 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #15 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #16 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #17 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #18 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #19 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #20 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #21 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #22 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #23 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #24 _PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8ae00)
        #25 PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8aeb4)
        #26 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27fbc0)
        #27 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #28 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #29 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #30 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #31 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #32 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #33 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #34 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #35 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #36 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #37 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #38 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #39 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #40 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #41 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #42 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #43 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #44 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #45 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #46 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #47 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #48 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #49 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #50 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #51 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #52 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #53 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #54 PyEval_EvalCode <null> (libpython3.14t.dylib:arm64+0x27886c)
        #55 run_mod <null> (libpython3.14t.dylib:arm64+0x346724)
        #56 _PyRun_SimpleFileObject <null> (libpython3.14t.dylib:arm64+0x341e10)
        #57 _PyRun_AnyFileObject <null> (libpython3.14t.dylib:arm64+0x341564)
        #58 pymain_run_file <null> (libpython3.14t.dylib:arm64+0x382acc)
        #59 Py_RunMain <null> (libpython3.14t.dylib:arm64+0x381ef8)
        #60 pymain_main <null> (libpython3.14t.dylib:arm64+0x382364)
        #61 Py_BytesMain <null> (libpython3.14t.dylib:arm64+0x382438)
        #62 main <null> (python3.14:arm64+0x10000070c)
    
      Thread T4 (tid=892058, running) created by main thread at:
        #0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x2f708)
        #1 do_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x36796c)
        #2 PyThread_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x3677b4)
        #3 do_start_new_thread <null> (libpython3.14t.dylib:arm64+0x4166bc)
        #4 thread_PyThread_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x415448)
        #5 cfunction_call <null> (libpython3.14t.dylib:arm64+0x12bfb4)
        #6 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #7 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #8 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2819d0)
        #9 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #10 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #11 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #12 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #13 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #14 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #15 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #16 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #17 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #18 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #19 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #20 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #21 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #22 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #23 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #24 _PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8ae00)
        #25 PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8aeb4)
        #26 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27fbc0)
        #27 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #28 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #29 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #30 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #31 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #32 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #33 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #34 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #35 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #36 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #37 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #38 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #39 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #40 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #41 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #42 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #43 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #44 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #45 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #46 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #47 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #48 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #49 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #50 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #51 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #52 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #53 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #54 PyEval_EvalCode <null> (libpython3.14t.dylib:arm64+0x27886c)
        #55 run_mod <null> (libpython3.14t.dylib:arm64+0x346724)
        #56 _PyRun_SimpleFileObject <null> (libpython3.14t.dylib:arm64+0x341e10)
        #57 _PyRun_AnyFileObject <null> (libpython3.14t.dylib:arm64+0x341564)
        #58 pymain_run_file <null> (libpython3.14t.dylib:arm64+0x382acc)
        #59 Py_RunMain <null> (libpython3.14t.dylib:arm64+0x381ef8)
        #60 pymain_main <null> (libpython3.14t.dylib:arm64+0x382364)
        #61 Py_BytesMain <null> (libpython3.14t.dylib:arm64+0x382438)
        #62 main <null> (python3.14:arm64+0x10000070c)
    
    SUMMARY: ThreadSanitizer: data race (_decimal.cpython-314t-darwin.so:arm64+0x98e4) in dec_addstatus+0x3c
    ==================
    ==================
    WARNING: ThreadSanitizer: data race (pid=10816)
      Write of size 4 at 0x00012305b23c by thread T1:
        #0 dec_addstatus <null> (_decimal.cpython-314t-darwin.so:arm64+0x98e4)
        #1 PyDecType_FromLongExact <null> (_decimal.cpython-314t-darwin.so:arm64+0x9c2c)
        #2 nm_mpd_qmul <null> (_decimal.cpython-314t-darwin.so:arm64+0x6164)
        #3 binary_op1 <null> (libpython3.14t.dylib:arm64+0x5acd8)
        #4 PyNumber_Multiply <null> (libpython3.14t.dylib:arm64+0x5ada4)
        #5 PyUFunc_OO_O <null> (_multiarray_umath.cpython-314t-darwin.so:arm64+0x78764)
        #6 PyObject_CallFunctionObjArgs <null> (libpython3.14t.dylib:arm64+0x8d110)
        #7 array_multiply <null> (_multiarray_umath.cpython-314t-darwin.so:arm64+0x138880)
        #8 PyNumber_Multiply <null> (libpython3.14t.dylib:arm64+0x5ada4)
        #9 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x279c44)
        #10 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #11 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #12 method_vectorcall <null> (libpython3.14t.dylib:arm64+0x8f638)
        #13 context_run <null> (libpython3.14t.dylib:arm64+0x2c3eec)
        #14 method_vectorcall_FASTCALL_KEYWORDS <null> (libpython3.14t.dylib:arm64+0xa1c48)
        #15 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ab8c)
        #16 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27ce94)
        #17 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #18 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #19 method_vectorcall <null> (libpython3.14t.dylib:arm64+0x8f638)
        #20 _PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8ae40)
        #21 PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8aeb4)
        #22 thread_run <null> (libpython3.14t.dylib:arm64+0x416b08)
        #23 pythread_wrapper <null> (libpython3.14t.dylib:arm64+0x368cac)
    
      Previous write of size 4 at 0x00012305b23c by thread T4:
        #0 dec_addstatus <null> (_decimal.cpython-314t-darwin.so:arm64+0x98e4)
        #1 PyDecType_FromLongExact <null> (_decimal.cpython-314t-darwin.so:arm64+0x9c2c)
        #2 nm_mpd_qmul <null> (_decimal.cpython-314t-darwin.so:arm64+0x6164)
        #3 binary_op1 <null> (libpython3.14t.dylib:arm64+0x5acd8)
        #4 PyNumber_Multiply <null> (libpython3.14t.dylib:arm64+0x5ada4)
        #5 PyUFunc_OO_O <null> (_multiarray_umath.cpython-314t-darwin.so:arm64+0x78764)
        #6 PyObject_CallFunctionObjArgs <null> (libpython3.14t.dylib:arm64+0x8d110)
        #7 array_multiply <null> (_multiarray_umath.cpython-314t-darwin.so:arm64+0x138880)
        #8 PyNumber_Multiply <null> (libpython3.14t.dylib:arm64+0x5ada4)
        #9 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x279c44)
        #10 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #11 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #12 method_vectorcall <null> (libpython3.14t.dylib:arm64+0x8f638)
        #13 context_run <null> (libpython3.14t.dylib:arm64+0x2c3eec)
        #14 method_vectorcall_FASTCALL_KEYWORDS <null> (libpython3.14t.dylib:arm64+0xa1c48)
        #15 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ab8c)
        #16 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27ce94)
        #17 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #18 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #19 method_vectorcall <null> (libpython3.14t.dylib:arm64+0x8f638)
        #20 _PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8ae40)
        #21 PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8aeb4)
        #22 thread_run <null> (libpython3.14t.dylib:arm64+0x416b08)
        #23 pythread_wrapper <null> (libpython3.14t.dylib:arm64+0x368cac)
    
      Thread T1 (tid=892055, running) created by main thread at:
        #0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x2f708)
        #1 do_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x36796c)
        #2 PyThread_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x3677b4)
        #3 do_start_new_thread <null> (libpython3.14t.dylib:arm64+0x4166bc)
        #4 thread_PyThread_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x415448)
        #5 cfunction_call <null> (libpython3.14t.dylib:arm64+0x12bfb4)
        #6 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #7 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #8 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #9 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #10 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #11 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #12 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #13 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #14 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #15 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #16 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #17 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #18 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #19 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #20 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #21 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #22 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #23 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #24 _PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8ae00)
        #25 PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8aeb4)
        #26 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27fbc0)
        #27 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #28 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #29 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #30 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #31 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #32 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #33 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #34 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #35 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #36 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #37 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #38 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #39 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #40 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #41 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #42 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #43 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #44 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #45 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #46 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #47 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #48 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #49 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #50 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #51 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #52 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #53 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #54 PyEval_EvalCode <null> (libpython3.14t.dylib:arm64+0x27886c)
        #55 run_mod <null> (libpython3.14t.dylib:arm64+0x346724)
        #56 _PyRun_SimpleFileObject <null> (libpython3.14t.dylib:arm64+0x341e10)
        #57 _PyRun_AnyFileObject <null> (libpython3.14t.dylib:arm64+0x341564)
        #58 pymain_run_file <null> (libpython3.14t.dylib:arm64+0x382acc)
        #59 Py_RunMain <null> (libpython3.14t.dylib:arm64+0x381ef8)
        #60 pymain_main <null> (libpython3.14t.dylib:arm64+0x382364)
        #61 Py_BytesMain <null> (libpython3.14t.dylib:arm64+0x382438)
        #62 main <null> (python3.14:arm64+0x10000070c)
    
      Thread T4 (tid=892058, running) created by main thread at:
        #0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x2f708)
        #1 do_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x36796c)
        #2 PyThread_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x3677b4)
        #3 do_start_new_thread <null> (libpython3.14t.dylib:arm64+0x4166bc)
        #4 thread_PyThread_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x415448)
        #5 cfunction_call <null> (libpython3.14t.dylib:arm64+0x12bfb4)
        #6 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #7 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #8 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2819d0)
        #9 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #10 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #11 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #12 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #13 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #14 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #15 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #16 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #17 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #18 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #19 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #20 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #21 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #22 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #23 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #24 _PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8ae00)
        #25 PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8aeb4)
        #26 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27fbc0)
        #27 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #28 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #29 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #30 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #31 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #32 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #33 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #34 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #35 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #36 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #37 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #38 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #39 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #40 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #41 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #42 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #43 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #44 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #45 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #46 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #47 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #48 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #49 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #50 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #51 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #52 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #53 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #54 PyEval_EvalCode <null> (libpython3.14t.dylib:arm64+0x27886c)
        #55 run_mod <null> (libpython3.14t.dylib:arm64+0x346724)
        #56 _PyRun_SimpleFileObject <null> (libpython3.14t.dylib:arm64+0x341e10)
        #57 _PyRun_AnyFileObject <null> (libpython3.14t.dylib:arm64+0x341564)
        #58 pymain_run_file <null> (libpython3.14t.dylib:arm64+0x382acc)
        #59 Py_RunMain <null> (libpython3.14t.dylib:arm64+0x381ef8)
        #60 pymain_main <null> (libpython3.14t.dylib:arm64+0x382364)
        #61 Py_BytesMain <null> (libpython3.14t.dylib:arm64+0x382438)
        #62 main <null> (python3.14:arm64+0x10000070c)
    
    SUMMARY: ThreadSanitizer: data race (_decimal.cpython-314t-darwin.so:arm64+0x98e4) in dec_addstatus+0x3c
    ==================
    ==================
    WARNING: ThreadSanitizer: data race (pid=10816)
      Write of size 4 at 0x00012305b23c by thread T4:
        #0 dec_addstatus <null> (_decimal.cpython-314t-darwin.so:arm64+0x98e4)
        #1 PyDecType_FromLongExact <null> (_decimal.cpython-314t-darwin.so:arm64+0x9c2c)
        #2 nm_mpd_qmul <null> (_decimal.cpython-314t-darwin.so:arm64+0x6164)
        #3 binary_op1 <null> (libpython3.14t.dylib:arm64+0x5acd8)
        #4 PyNumber_Multiply <null> (libpython3.14t.dylib:arm64+0x5ada4)
        #5 PyUFunc_OO_O <null> (_multiarray_umath.cpython-314t-darwin.so:arm64+0x78764)
        #6 PyObject_CallFunctionObjArgs <null> (libpython3.14t.dylib:arm64+0x8d110)
        #7 array_multiply <null> (_multiarray_umath.cpython-314t-darwin.so:arm64+0x138880)
        #8 PyNumber_Multiply <null> (libpython3.14t.dylib:arm64+0x5ada4)
        #9 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x279c44)
        #10 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #11 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #12 method_vectorcall <null> (libpython3.14t.dylib:arm64+0x8f638)
        #13 context_run <null> (libpython3.14t.dylib:arm64+0x2c3eec)
        #14 method_vectorcall_FASTCALL_KEYWORDS <null> (libpython3.14t.dylib:arm64+0xa1c48)
        #15 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ab8c)
        #16 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27ce94)
        #17 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #18 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #19 method_vectorcall <null> (libpython3.14t.dylib:arm64+0x8f638)
        #20 _PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8ae40)
        #21 PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8aeb4)
        #22 thread_run <null> (libpython3.14t.dylib:arm64+0x416b08)
        #23 pythread_wrapper <null> (libpython3.14t.dylib:arm64+0x368cac)
    
      Previous write of size 4 at 0x00012305b23c by thread T1:
        #0 dec_addstatus <null> (_decimal.cpython-314t-darwin.so:arm64+0x98e4)
        #1 nm_mpd_qmul <null> (_decimal.cpython-314t-darwin.so:arm64+0x6468)
        #2 binary_op1 <null> (libpython3.14t.dylib:arm64+0x5acd8)
        #3 PyNumber_Multiply <null> (libpython3.14t.dylib:arm64+0x5ada4)
        #4 PyUFunc_OO_O <null> (_multiarray_umath.cpython-314t-darwin.so:arm64+0x78764)
        #5 PyObject_CallFunctionObjArgs <null> (libpython3.14t.dylib:arm64+0x8d110)
        #6 array_multiply <null> (_multiarray_umath.cpython-314t-darwin.so:arm64+0x138880)
        #7 PyNumber_Multiply <null> (libpython3.14t.dylib:arm64+0x5ada4)
        #8 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x279c44)
        #9 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #10 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #11 method_vectorcall <null> (libpython3.14t.dylib:arm64+0x8f638)
        #12 context_run <null> (libpython3.14t.dylib:arm64+0x2c3eec)
        #13 method_vectorcall_FASTCALL_KEYWORDS <null> (libpython3.14t.dylib:arm64+0xa1c48)
        #14 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ab8c)
        #15 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27ce94)
        #16 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #17 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #18 method_vectorcall <null> (libpython3.14t.dylib:arm64+0x8f638)
        #19 _PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8ae40)
        #20 PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8aeb4)
        #21 thread_run <null> (libpython3.14t.dylib:arm64+0x416b08)
        #22 pythread_wrapper <null> (libpython3.14t.dylib:arm64+0x368cac)
    
      Thread T4 (tid=892058, running) created by main thread at:
        #0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x2f708)
        #1 do_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x36796c)
        #2 PyThread_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x3677b4)
        #3 do_start_new_thread <null> (libpython3.14t.dylib:arm64+0x4166bc)
        #4 thread_PyThread_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x415448)
        #5 cfunction_call <null> (libpython3.14t.dylib:arm64+0x12bfb4)
        #6 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #7 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #8 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2819d0)
        #9 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #10 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #11 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #12 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #13 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #14 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #15 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #16 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #17 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #18 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #19 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #20 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #21 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #22 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #23 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #24 _PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8ae00)
        #25 PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8aeb4)
        #26 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27fbc0)
        #27 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #28 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #29 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #30 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #31 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #32 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #33 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #34 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #35 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #36 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #37 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #38 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #39 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #40 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #41 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #42 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #43 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #44 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #45 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #46 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #47 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #48 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #49 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #50 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #51 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #52 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #53 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #54 PyEval_EvalCode <null> (libpython3.14t.dylib:arm64+0x27886c)
        #55 run_mod <null> (libpython3.14t.dylib:arm64+0x346724)
        #56 _PyRun_SimpleFileObject <null> (libpython3.14t.dylib:arm64+0x341e10)
        #57 _PyRun_AnyFileObject <null> (libpython3.14t.dylib:arm64+0x341564)
        #58 pymain_run_file <null> (libpython3.14t.dylib:arm64+0x382acc)
        #59 Py_RunMain <null> (libpython3.14t.dylib:arm64+0x381ef8)
        #60 pymain_main <null> (libpython3.14t.dylib:arm64+0x382364)
        #61 Py_BytesMain <null> (libpython3.14t.dylib:arm64+0x382438)
        #62 main <null> (python3.14:arm64+0x10000070c)
    
      Thread T1 (tid=892055, running) created by main thread at:
        #0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x2f708)
        #1 do_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x36796c)
        #2 PyThread_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x3677b4)
        #3 do_start_new_thread <null> (libpython3.14t.dylib:arm64+0x4166bc)
        #4 thread_PyThread_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x415448)
        #5 cfunction_call <null> (libpython3.14t.dylib:arm64+0x12bfb4)
        #6 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #7 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #8 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #9 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #10 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #11 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #12 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #13 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #14 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #15 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #16 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #17 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #18 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #19 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #20 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #21 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #22 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #23 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #24 _PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8ae00)
        #25 PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8aeb4)
        #26 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27fbc0)
        #27 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #28 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #29 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #30 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #31 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #32 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #33 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #34 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #35 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #36 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #37 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #38 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #39 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #40 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #41 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #42 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #43 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #44 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #45 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #46 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #47 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #48 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #49 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #50 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #51 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #52 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #53 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #54 PyEval_EvalCode <null> (libpython3.14t.dylib:arm64+0x27886c)
        #55 run_mod <null> (libpython3.14t.dylib:arm64+0x346724)
        #56 _PyRun_SimpleFileObject <null> (libpython3.14t.dylib:arm64+0x341e10)
        #57 _PyRun_AnyFileObject <null> (libpython3.14t.dylib:arm64+0x341564)
        #58 pymain_run_file <null> (libpython3.14t.dylib:arm64+0x382acc)
        #59 Py_RunMain <null> (libpython3.14t.dylib:arm64+0x381ef8)
        #60 pymain_main <null> (libpython3.14t.dylib:arm64+0x382364)
        #61 Py_BytesMain <null> (libpython3.14t.dylib:arm64+0x382438)
        #62 main <null> (python3.14:arm64+0x10000070c)
    
    SUMMARY: ThreadSanitizer: data race (_decimal.cpython-314t-darwin.so:arm64+0x98e4) in dec_addstatus+0x3c
    ==================
    ==================
    WARNING: ThreadSanitizer: data race (pid=10816)
      Write of size 4 at 0x00012305b23c by thread T1:
        #0 dec_addstatus <null> (_decimal.cpython-314t-darwin.so:arm64+0x98e4)
        #1 nm_mpd_qmul <null> (_decimal.cpython-314t-darwin.so:arm64+0x6468)
        #2 binary_op1 <null> (libpython3.14t.dylib:arm64+0x5acd8)
        #3 PyNumber_Multiply <null> (libpython3.14t.dylib:arm64+0x5ada4)
        #4 PyUFunc_OO_O <null> (_multiarray_umath.cpython-314t-darwin.so:arm64+0x78764)
        #5 PyObject_CallFunctionObjArgs <null> (libpython3.14t.dylib:arm64+0x8d110)
        #6 array_multiply <null> (_multiarray_umath.cpython-314t-darwin.so:arm64+0x138880)
        #7 PyNumber_Multiply <null> (libpython3.14t.dylib:arm64+0x5ada4)
        #8 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x279c44)
        #9 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #10 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #11 method_vectorcall <null> (libpython3.14t.dylib:arm64+0x8f638)
        #12 context_run <null> (libpython3.14t.dylib:arm64+0x2c3eec)
        #13 method_vectorcall_FASTCALL_KEYWORDS <null> (libpython3.14t.dylib:arm64+0xa1c48)
        #14 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ab8c)
        #15 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27ce94)
        #16 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #17 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #18 method_vectorcall <null> (libpython3.14t.dylib:arm64+0x8f638)
        #19 _PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8ae40)
        #20 PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8aeb4)
        #21 thread_run <null> (libpython3.14t.dylib:arm64+0x416b08)
        #22 pythread_wrapper <null> (libpython3.14t.dylib:arm64+0x368cac)
    
      Previous write of size 4 at 0x00012305b23c by thread T4:
        #0 dec_addstatus <null> (_decimal.cpython-314t-darwin.so:arm64+0x98e4)
        #1 nm_mpd_qmul <null> (_decimal.cpython-314t-darwin.so:arm64+0x6468)
        #2 binary_op1 <null> (libpython3.14t.dylib:arm64+0x5acd8)
        #3 PyNumber_Multiply <null> (libpython3.14t.dylib:arm64+0x5ada4)
        #4 PyUFunc_OO_O <null> (_multiarray_umath.cpython-314t-darwin.so:arm64+0x78764)
        #5 PyObject_CallFunctionObjArgs <null> (libpython3.14t.dylib:arm64+0x8d110)
        #6 array_multiply <null> (_multiarray_umath.cpython-314t-darwin.so:arm64+0x138880)
        #7 PyNumber_Multiply <null> (libpython3.14t.dylib:arm64+0x5ada4)
        #8 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x279c44)
        #9 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #10 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #11 method_vectorcall <null> (libpython3.14t.dylib:arm64+0x8f638)
        #12 context_run <null> (libpython3.14t.dylib:arm64+0x2c3eec)
        #13 method_vectorcall_FASTCALL_KEYWORDS <null> (libpython3.14t.dylib:arm64+0xa1c48)
        #14 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ab8c)
        #15 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27ce94)
        #16 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #17 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #18 method_vectorcall <null> (libpython3.14t.dylib:arm64+0x8f638)
        #19 _PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8ae40)
        #20 PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8aeb4)
        #21 thread_run <null> (libpython3.14t.dylib:arm64+0x416b08)
        #22 pythread_wrapper <null> (libpython3.14t.dylib:arm64+0x368cac)
    
      Thread T1 (tid=892055, running) created by main thread at:
        #0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x2f708)
        #1 do_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x36796c)
        #2 PyThread_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x3677b4)
        #3 do_start_new_thread <null> (libpython3.14t.dylib:arm64+0x4166bc)
        #4 thread_PyThread_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x415448)
        #5 cfunction_call <null> (libpython3.14t.dylib:arm64+0x12bfb4)
        #6 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #7 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #8 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #9 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #10 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #11 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #12 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #13 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #14 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #15 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #16 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #17 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #18 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #19 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #20 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #21 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #22 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #23 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #24 _PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8ae00)
        #25 PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8aeb4)
        #26 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27fbc0)
        #27 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #28 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #29 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #30 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #31 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #32 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #33 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #34 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #35 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #36 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #37 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #38 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #39 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #40 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #41 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #42 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #43 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #44 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #45 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #46 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #47 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #48 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #49 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #50 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #51 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #52 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #53 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #54 PyEval_EvalCode <null> (libpython3.14t.dylib:arm64+0x27886c)
        #55 run_mod <null> (libpython3.14t.dylib:arm64+0x346724)
        #56 _PyRun_SimpleFileObject <null> (libpython3.14t.dylib:arm64+0x341e10)
        #57 _PyRun_AnyFileObject <null> (libpython3.14t.dylib:arm64+0x341564)
        #58 pymain_run_file <null> (libpython3.14t.dylib:arm64+0x382acc)
        #59 Py_RunMain <null> (libpython3.14t.dylib:arm64+0x381ef8)
        #60 pymain_main <null> (libpython3.14t.dylib:arm64+0x382364)
        #61 Py_BytesMain <null> (libpython3.14t.dylib:arm64+0x382438)
        #62 main <null> (python3.14:arm64+0x10000070c)
    
      Thread T4 (tid=892058, running) created by main thread at:
        #0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x2f708)
        #1 do_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x36796c)
        #2 PyThread_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x3677b4)
        #3 do_start_new_thread <null> (libpython3.14t.dylib:arm64+0x4166bc)
        #4 thread_PyThread_start_joinable_thread <null> (libpython3.14t.dylib:arm64+0x415448)
        #5 cfunction_call <null> (libpython3.14t.dylib:arm64+0x12bfb4)
        #6 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #7 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #8 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2819d0)
        #9 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #10 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #11 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #12 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #13 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #14 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #15 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #16 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #17 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #18 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #19 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #20 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #21 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #22 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #23 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #24 _PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8ae00)
        #25 PyObject_Call <null> (libpython3.14t.dylib:arm64+0x8aeb4)
        #26 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x27fbc0)
        #27 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #28 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #29 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #30 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #31 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #32 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #33 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #34 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #35 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #36 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #37 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #38 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #39 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #40 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #41 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #42 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #43 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #44 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #45 _PyEval_Vector <null> (libpython3.14t.dylib:arm64+0x278c90)
        #46 _PyFunction_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8b1cc)
        #47 _PyObject_VectorcallDictTstate <null> (libpython3.14t.dylib:arm64+0x89d98)
        #48 _PyObject_Call_Prepend <null> (libpython3.14t.dylib:arm64+0x8b7dc)
        #49 call_method <null> (libpython3.14t.dylib:arm64+0x196a54)
        #50 slot_tp_call <null> (libpython3.14t.dylib:arm64+0x196874)
        #51 _PyObject_MakeTpCall <null> (libpython3.14t.dylib:arm64+0x8a038)
        #52 PyObject_Vectorcall <null> (libpython3.14t.dylib:arm64+0x8ac28)
        #53 _PyEval_EvalFrameDefault <null> (libpython3.14t.dylib:arm64+0x2809ac)
        #54 PyEval_EvalCode <null> (libpython3.14t.dylib:arm64+0x27886c)
        #55 run_mod <null> (libpython3.14t.dylib:arm64+0x346724)
        #56 _PyRun_SimpleFileObject <null> (libpython3.14t.dylib:arm64+0x341e10)
        #57 _PyRun_AnyFileObject <null> (libpython3.14t.dylib:arm64+0x341564)
        #58 pymain_run_file <null> (libpython3.14t.dylib:arm64+0x382acc)
        #59 Py_RunMain <null> (libpython3.14t.dylib:arm64+0x381ef8)
        #60 pymain_main <null> (libpython3.14t.dylib:arm64+0x382364)
        #61 Py_BytesMain <null> (libpython3.14t.dylib:arm64+0x382438)
        #62 main <null> (python3.14:arm64+0x10000070c)
    
    SUMMARY: ThreadSanitizer: data race (_decimal.cpython-314t-darwin.so:arm64+0x98e4) in dec_addstatus+0x3c
    ==================
    ThreadSanitizer: reported 4 warnings
    
  5. skirpichev commented on Nov 22, 2025

    @skirpichev
    Member

    I confirm. This happens on v3.14.0 with (commented variant affected too):

    # test_a.py
    from decimal import Decimal
    
    def test_array_gcd_lcm_decimal():
    #   a = 123 * Decimal('0.20')
        a = 123 * Decimal(123)
        assert a

    (Edit: "fixed" by export PYTHON_THREAD_INHERIT_CONTEXT=0.)

  6. colesbury commented on Nov 22, 2025

    @colesbury
    Contributor

    This is tricky. I'm not sure what the fix should be, but I no longer think it's just a documentation issue (or API misuse).

    I think the underlying problem is that the Decimal context is a single context var, so you don't get the thread-safety (or context safety) that you'd normally expect with context vars.

  7. skirpichev commented on Nov 22, 2025

    @skirpichev
    Member

    I think the underlying problem is that the Decimal context is a single context var

    Hmm, this is same as for the gmpy2 extension module. Though, it works in a similar situation (status flags got updated in example below):

    # test_b.py
    from gmpy2 import mpfr
    
    def test_gmpy2():
        a = 1.1 * mpfr(123)
        assert a
  8. kumaraditya303 commented on Nov 25, 2025

    @kumaraditya303
    ContributorAuthor

    Another reproducer which does not shares a global context:

    I was able to fix this case with the following patch:

    diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c
    index 0484d9896a1..8fc1183b648 100644
    --- a/Modules/_decimal/_decimal.c
    +++ b/Modules/_decimal/_decimal.c
    @@ -1941,7 +1941,24 @@ current_context(decimal_state *state)
         }
     
         if (tl_context != NULL) {
    -        return tl_context;
    +        // It is possible that the context was inherited from another thread
    +        // e.g. if PYTHON_THREAD_INHERIT_CONTEXT=1 is set.
    +        // In that case, we need to make a copy of context otherwise we
    +        // would be sharing the same context as the parent thread.
    +        // This is needed as decimal module mutates the context directly
    +        // rather than setting a new context via PyContextVar_Set.
    +        PyThreadState *tstate = _PyThreadState_GET();
    +        if (_PyDecContextObject_CAST(tl_context)->tstate == tstate) {
    +            return tl_context;
    +        }
    +        PyObject *copy = context_copy(state, tl_context);
    +        Py_INCREF(copy);
    +        // Set the copy as the current context for this thread,
    +        // so that subsequent calls get the correct context.
    +        PyObject *tok = PyContextVar_Set(state->current_context_var, copy);
    +        Py_DECREF(tok);
    +        Py_DECREF(tl_context);
    +        return copy;
         }
     
         return init_current_context(state);
    

    With this I don't see any data races with the minimal reproducer which does not shares global context.

  9. colesbury commented on Nov 25, 2025

    @colesbury
    Contributor

    The copying in the patch is happening when the context is accessed. It can still be concurrently modified by the parent thread.

  10. self-assigned this
    on Dec 5, 2025
  11. skirpichev commented on Dec 5, 2025

    @skirpichev
    Member

    The copying in the patch is happening when the context is accessed. It can still be concurrently modified by the parent thread.

    I think this case is already covered by docs:

    To control the defaults so that each thread will use the same values throughout the application, directly modify the DefaultContext object. This should be done before any threads are started so that there won’t be a race condition between threads calling getcontext().

  12. LindaSummer commented on Mar 13, 2026

    @LindaSummer
    Contributor

    Hi @skirpichev @colesbury @kumaraditya303 ,
    Are we still working on this issue?
    If this problem needs to be solved, I want to have a try. 😊

  13. skirpichev commented on Mar 13, 2026

    @skirpichev
    Member

    If this problem needs to be solved

    I think so.

    I want to have a try.

    Feel free to do this. Beware, it may be not an easy issue.

  14. skirpichev commented on Mar 22, 2026

    @skirpichev
    Member

    After some experiments, I feel that #130010 breaks the decimal module. And not only it's C-version. Lets consider the pure-Python module.

    Docs now says:

    If setcontext() has not been called before getcontext(), then getcontext() will automatically create a new context for use in the current thread. New context objects have default values set from the decimal.DefaultContext object.

    The sys.flags.thread_inherit_context flag affects the context for new threads. If the flag is false, new threads will start with an empty context. In this case, getcontext() will create a new context object when called and use the default values from DefaultContext. If the flag is true, new threads will start with a copy of context from the caller of threading.Thread.start().

    First, the last sentence is misleading. The context, referred here ("a copy of") is not a decimal Context.

    Second, in fact, with this settings --- thread rather inherits parents context, if we are talking about decimal's Context. That could be demonstrated by:

    from threading import Thread, Barrier
    from _pydecimal import *
    #from decimal import *
    
    DefaultContext.prec = 12
    setcontext(DefaultContext)
    n = 3
    barrier = Barrier(n)
    
    def race(i, r):
        barrier.wait()
        ctx = getcontext()
        ctx.prec += i
        ctx.clear_flags()
        d = Decimal('1E-100000000')
        if i % 2 == 0:
            d = +d
        r[i] = (i, ctx.prec, id(ctx), int(ctx.flags[Underflow]))
    
    if __name__ == "__main__":
        for _ in range(n):
            r = list(range(n))
            threads = [Thread(target=race, args=(i, r)) for i in range(n)]
    #       threads = [Thread(target=race, args=(i, r),
    #                         context=contextvars.Context()) for i in range(n)]
            for thread in threads:
                thread.start()
            for thread in threads:
                thread.join()
            print(r)

    Output:

    $ PYTHON_THREAD_INHERIT_CONTEXT=0 ./python d.py
    [(0, 12, 139845881823648, 1), (1, 13, 139845948932448, 0), (2, 14, 139846015254944, 1)]
    [(0, 12, 139845949194592, 1), (1, 13, 139845882085728, 0), (2, 14, 139846016434528, 1)]
    [(0, 12, 139845948932448, 1), (1, 13, 139845881561376, 0), (2, 14, 139846016237920, 1)]
    $ PYTHON_THREAD_INHERIT_CONTEXT=1 ./python d.py
    [(0, 14, 140482748631840, 1), (1, 14, 140482748631840, 1), (2, 14, 140482748631840, 1)]
    [(0, 17, 140482748631840, 1), (1, 17, 140482748631840, 0), (2, 17, 140482748631840, 1)]
    [(0, 20, 140482748631840, 1), (1, 20, 140482748631840, 0), (2, 20, 140482748631840, 1)]
    

    For C-decimal module the last example will trigger TS failure like in the issue description

    This looks as a regression, because the leading paragraph of the Working with threads section says:

    The getcontext() function accesses a different Context object for each thread. Having separate thread contexts means that threads may make changes (such as getcontext().prec=10) without interfering with other threads.

    Now this contract is broken with PYTHON_THREAD_INHERIT_CONTEXT=1 settings, i.e. per default on free-threading builds.

    CC @nascheme

    BTW, workaround is commented out in the code (explicit settings of the context parameter for Thread). So, maybe it's still a documentation issue. Documentation must be fixed anyway, so I'll add a label.

  15. removed their assignment
    on Mar 22, 2026
  16. nascheme commented on Mar 26, 2026

    @nascheme
    Member

    Yeah, there is bug here and it's not just a documentation issue. IMHO, the original change that switched _current_context_var to be contextvars.ContextVar rather than threading.local() was the start of problem. Or, maybe you could say it was broken before that, since the decimal context did not function as expected when async tasks were involved. Using ContextVar() instead of thread-locals was an attempt make things work nicely with asyncio but didn't really do it.

    The problem with using ContextVar() is that the copy operation done, via the HAMT data structure, applies to the bindings and not to the variables themselves. For the decimal module, the bound variable is a Context() instance and it itself is mutable.

    The names involved here are adding to the confusion. E.g. this text:

    If the flag is true, new threads will start with a copy of context from the caller of threading.Thread.start().

    Is true if we mean "context" as in a contextvars.Context() instance. It's not true for the decimal Context() instance though. As you point out, this documentation is definitely not correct right now:

    The getcontext() function accesses a different Context object for each thread. Having separate thread contexts means that threads may make changes (such as getcontext().prec=10) without interfering with other threads.

    I think I have a fix for this, will make a PR. It should both fix the problem with threads and also for asyncio.

  17. nascheme commented on Mar 26, 2026

    @nascheme
    Member

    It seems GH-146482 will fix this race if we don't share a global context. My reproducer code (produces TSAN warnings without the PR and no warnings with):

    from decimal import Decimal, getcontext
    import threading
    
    
    def decimal_work():
        a = 123 * Decimal("0.20")
        assert a
    
    
    def race():
        barrier.wait(timeout=2)
        for _ in range(100):
            decimal_work()
    
    
    if __name__ == "__main__":
        N_THREADS = 20
        barrier = threading.Barrier(N_THREADS)
        for _ in range(10):
            ctx = getcontext()  # need to set context in parent thread
            threads = [threading.Thread(target=race) for _ in range(N_THREADS)]
            for thread in threads:
                thread.start()
            for thread in threads:
                thread.join()
  18. devdanzin commented on Apr 29, 2026

    @devdanzin
    Member

    Just to flag a scope question for after #146482 lands:

    The PR closes the inherited-context path — getcontext() / current_context() now copy on first access in a new thread/task, so default arithmetic stops racing on a shared mpd_context_t.

    It doesn't, however, close the underlying primitive race in _decimal.c. Those accesses are still plain non-atomic reads/writes:

    • dec_addstatus: ctx->status |= status; at _decimal.c:616
    • Context.clear_flags: ctx->status = 0; at _decimal.c:1421
    • Context.clear_traps: ctx->traps = 0; at _decimal.c:1407
    • signaldict_setitem: SdFlags(self) |= flag; / SdFlags(self) &= ~flag; at _decimal.c:744 / :747 (this is ctx->status / ctx->traps reached via ctx.flags[...] = True)
    • signaldict_getitem: SdFlags(self) & flag at _decimal.c:715

    So the race still fires whenever the same Context is reached without going through current_context(). In particular, this issue's own MRE:

    context = decimal.Context()
    context.prec = 28
    ...
    def race():
        barrier.wait()
        decimal.Decimal('1.0', context=context)

    passes context=context explicitly and so bypasses the new get_changed()-based copy. After #146482 merges that exact reproducer should still trip TSan at _decimal.c:616. Same for any of:

    • shared_ctx.create_decimal(s) (routes through _decimal_Context_create_decimal_impl)
    • shared_ctx.add(...) / multiply / divide / quantize / etc.
    • shared_ctx.flags[Inexact] = True concurrent with arithmetic
    • setcontext(non_template_instance) from multiple threads (only the three module templates are auto-copied; other instances are Py_INCREF'd and stored as-is)

    I'd suggest either keeping this issue open until those C-level sites are made FT-safe (atomic ops or a per-Context PyMutex), or, probably cleaner, letting #146482 close this one and tracking the primitive in a follow-up. Happy to file that follow-up with reproducers for each of the five sites if helpful.

    Drafted by Claude Code, reviewed by a human.

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

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions