Reproducer:
importdecimalfromthreadingimportThread, Barriercontext=decimal.Context()
context.prec=28barrier=Barrier(10)
defrace():
barrier.wait()
decimal.Decimal('1.0', context=context)
if__name__=="__main__":
whileTrue:
threads= [Thread(target=race) for_inrange(10)]
forthreadinthreads:
thread.start()
forthreadinthreads:
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
Reproducer:
Data race:
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