GeezerVison is showing github.com — `tracemalloc` aborts when run from threads in no-gil · Issue #126315 · python/cpython
tracemalloc aborts when run from threads in no-gil #126315
DescriptionCrash report
What happened?
It's possible to get two different aborts from failed assertions, only with PYTHON_GIL=0, using the code below:
from threading import Thread
import _tracemalloc
alive = [
Thread(target=_tracemalloc.start, args=(
(memoryview(bytearray(b"abc\xe9\xff")),))),
Thread(target=_tracemalloc.start, args=()),
Thread(target=_tracemalloc.get_traceback_limit, args=()),
Thread(target=_tracemalloc.start, args=()),
Thread(target=_tracemalloc.stop, args=()),
Thread(target=_tracemalloc.reset_peak, args=()),
Thread(target=_tracemalloc.get_tracemalloc_memory, args=())
]
for obj in alive:
print('START', obj)
try:
obj.start()
except Exception:
pass
The errors are:
python: Python/tracemalloc.c:445: tracemalloc_remove_trace: Assertion `tracemalloc_config.tracing' failed.
Aborted
And:
python: Python/tracemalloc.c:469: tracemalloc_add_trace: Assertion `tracemalloc_config.tracing' failed.
Aborted
Found with fusil by @vstinner.
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
Python 3.14.0a1+ experimental free-threading build (heads/main:d467d9246c, Nov 1 2024, 09:05:56) [GCC 11.4.0] Activityrruuaanng commented on Nov 4, 2024 Maybe we can add HEAD lock to tracemalloc_config.tracing. This is most likely caused by concurrent operations on a global without locking. If possible, I'll make a PR. devdanzin commented on May 2, 2025 Cannot repro anymore, please re-open if you can. devdanzin commented on May 2, 2025 Oops, maybe spoke too soon: it segfaults on a release build if we create more threads and try more times!
from threading import Thread
import _tracemalloc
for x in range(20):
alive = []
for x in range(500):
alive += [
Thread(target=_tracemalloc.start, args=(
(1,))),
Thread(target=_tracemalloc.start, args=()),
Thread(target=_tracemalloc.get_traceback_limit, args=()),
Thread(target=_tracemalloc.start, args=()),
Thread(target=_tracemalloc.stop, args=()),
Thread(target=_tracemalloc.reset_peak, args=()),
Thread(target=_tracemalloc.get_tracemalloc_memory, args=())
]
for obj in alive:
print('START', obj)
try:
obj.start()
except Exception:
pass
Thread 1 "python" received signal SIGSEGV, Segmentation fault.
tracemalloc_free (ctx=0x0, ptr=0x545fa2b3b40) at Python/tracemalloc.c:642
642 alloc->free(alloc->ctx, ptr);
#0 tracemalloc_free (ctx=0x0, ptr=0x545fa2b3b40) at Python/tracemalloc.c:642
#1 0x000055555565c993 in free_list_items (items=<optimized out>, use_qsbr=<optimized out>) at Objects/listobject.c:67
#2 list_resize (self=self@entry=0x545fa94c440, newsize=newsize@entry=3) at Objects/listobject.c:167
#3 0x000055555565ca9b in _PyList_AppendTakeRefListResize (self=0x545fa94c440, newitem=0x545fa1edf80)
at Objects/listobject.c:523
#4 _PyList_AppendTakeRef (self=0x545fa94c440, newitem=0x545fa1edf80) at ./Include/internal/pycore_list.h:48
#5 PyList_Append (op=0x545fa94c440, newitem=newitem@entry=0x545fa1edf80) at Objects/listobject.c:537
#6 0x0000555555846f23 in _io_TextIOWrapper_write_impl (self=0x545fa384ec0, text=<optimized out>)
at ./Modules/_io/textio.c:1769
#7 _io_TextIOWrapper_write (self=0x545fa384ec0, arg=<optimized out>) at ./Modules/_io/clinic/textio.c.h:803
#8 0x000055555562ce97 in _PyObject_VectorcallTstate (tstate=0x555555ae92c8 <_PyRuntime+345608>, callable=0x545fa87d8e0,
args=0x545fa2b3b40, nargsf=9223372036854775809, kwnames=0x0) at ./Include/internal/pycore_call.h:169
#9 PyObject_CallOneArg (func=func@entry=0x545fa87d8e0, arg=arg@entry=0x545fa1edf80) at Objects/call.c:395
#10 0x000055555564ce07 in PyFile_WriteObject (v=0x545fa7a0710, f=f@entry=0x545fa384ec0, flags=flags@entry=1)
at Objects/fileobject.c:127
#11 0x000055555575f6cc in builtin_print_impl (args=<optimized out>, args_length=<optimized out>, sep=<optimized out>, end=0x0,
file=0x545fa384ec0, flush=<optimized out>, module=<optimized out>) at Python/bltinmodule.c:2218
#12 builtin_print (module=<optimized out>, args=0x7fffffffcf18, nargs=2, kwnames=<optimized out>)
at Python/clinic/bltinmodule.c.h:1010
#13 0x000055555576f051 in _PyEval_EvalFrameDefault (tstate=0x555555ae92c8 <_PyRuntime+345608>, frame=0x7ffff7faf020,
throwflag=<optimized out>) at Python/generated_cases.c.h:2204
#14 0x00005555557625d8 in _PyEval_EvalFrame (tstate=0x555555ae92c8 <_PyRuntime+345608>, frame=0x545fa2b3b40, throwflag=0)
at ./Include/internal/pycore_ceval.h:119
#15 _PyEval_Vector (tstate=0x555555ae92c8 <_PyRuntime+345608>, func=0x545fa8ceac0, locals=0x545fa942680, args=0x0, argcount=0,
kwnames=0x0) at Python/ceval.c:1917
#16 PyEval_EvalCode (co=co@entry=0x545fa444e00, globals=globals@entry=0x545fa942680, locals=locals@entry=0x545fa942680)
at Python/ceval.c:829
#17 0x00005555557e7540 in run_eval_code_obj (tstate=0x555555ae92c8 <_PyRuntime+345608>, co=0x545fa444e00,
globals=0x545fa942680, locals=0x545fa942680) at Python/pythonrun.c:1365kumaraditya303 commented on Jul 8, 2025 I looked into the thread safety of tracemalloc and there are a few thread safety issues here:
Data races:
Details
==================
WARNING: ThreadSanitizer: data race (pid=77186)
Write of size 8 at 0x000104afd6e8 by thread T1:
#0 PyRefTracer_SetTracer object.c:3296 (python.exe:arm64+0x10012fd8c)
#1 _PyTraceMalloc_Start tracemalloc.c:837 (python.exe:arm64+0x10035ba9c)
#2 _tracemalloc_start _tracemalloc.c.h:111 (python.exe:arm64+0x100390244)
#3 cfunction_vectorcall_FASTCALL methodobject.c:449 (python.exe:arm64+0x10011eee8)
#4 _PyObject_Call call.c:348 (python.exe:arm64+0x10007f1cc)
#5 PyObject_Call call.c:373 (python.exe:arm64+0x10007f240)
#6 _PyEval_EvalFrameDefault generated_cases.c.h:2656 (python.exe:arm64+0x10027b0f0)
#7 _PyEval_Vector ceval.c:1977 (python.exe:arm64+0x10026a10c)
#8 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007f554)
#9 method_vectorcall classobject.c:73 (python.exe:arm64+0x100083a94)
#10 context_run context.c:728 (python.exe:arm64+0x1002b4c3c)
#11 method_vectorcall_FASTCALL_KEYWORDS descrobject.c:421 (python.exe:arm64+0x1000963e8)
#12 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x10007ef1c)
#13 _PyEval_EvalFrameDefault generated_cases.c.h:1620 (python.exe:arm64+0x100276ee8)
#14 _PyEval_Vector ceval.c:1977 (python.exe:arm64+0x10026a10c)
#15 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007f554)
#16 method_vectorcall classobject.c:73 (python.exe:arm64+0x100083a94)
#17 _PyObject_Call call.c:348 (python.exe:arm64+0x10007f1cc)
#18 PyObject_Call call.c:373 (python.exe:arm64+0x10007f240)
#19 thread_run _threadmodule.c:373 (python.exe:arm64+0x1003ee358)
#20 pythread_wrapper thread_pthread.h:232 (python.exe:arm64+0x100356ff8)
Previous read of size 8 at 0x000104afd6e8 by main thread:
#0 _Py_Dealloc object.c:3205 (python.exe:arm64+0x100126350)
#1 _Py_MergeZeroLocalRefcount object.c (python.exe:arm64+0x100126600)
#2 method_vectorcall_VARARGS descrobject.c:327 (python.exe:arm64+0x100095f74)
#3 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x10007ef1c)
#4 _PyEval_EvalFrameDefault generated_cases.c.h:4101 (python.exe:arm64+0x1002773f8)
#5 PyEval_EvalCode ceval.c:868 (python.exe:arm64+0x100269ce8)
#6 run_mod pythonrun.c:1436 (python.exe:arm64+0x100335258)
#7 _PyRun_SimpleFileObject pythonrun.c:521 (python.exe:arm64+0x100330a84)
#8 _PyRun_AnyFileObject pythonrun.c:81 (python.exe:arm64+0x1003301dc)
#9 pymain_run_file main.c:429 (python.exe:arm64+0x10036fe18)
#10 Py_RunMain main.c:772 (python.exe:arm64+0x10036f24c)
#11 pymain_main main.c:802 (python.exe:arm64+0x10036f6b8)
#12 Py_BytesMain main.c:826 (python.exe:arm64+0x10036f78c)
#13 main python.c:15 (python.exe:arm64+0x1000009b4)
Location is global '_PyRuntime' at 0x000104afb040 (python.exe+0x1006416e8)
Thread T1 (tid=421140, running) created by main thread at:
#0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x32b00)
#1 do_start_joinable_thread thread_pthread.h:279 (python.exe:arm64+0x100356250)
#2 PyThread_start_joinable_thread thread_pthread.h:321 (python.exe:arm64+0x100356098)
#3 do_start_new_thread _threadmodule.c:1877 (python.exe:arm64+0x1003edf0c)
#4 thread_PyThread_start_joinable_thread _threadmodule.c:1992 (python.exe:arm64+0x1003ecc9c)
#5 cfunction_call methodobject.c:564 (python.exe:arm64+0x10011fc44)
#6 _PyObject_MakeTpCall call.c:242 (python.exe:arm64+0x10007e3cc)
#7 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x10007efb8)
#8 _PyEval_EvalFrameDefault generated_cases.c.h:2968 (python.exe:arm64+0x10027c190)
#9 PyEval_EvalCode ceval.c:868 (python.exe:arm64+0x100269ce8)
#10 run_mod pythonrun.c:1436 (python.exe:arm64+0x100335258)
#11 _PyRun_SimpleFileObject pythonrun.c:521 (python.exe:arm64+0x100330a84)
#12 _PyRun_AnyFileObject pythonrun.c:81 (python.exe:arm64+0x1003301dc)
#13 pymain_run_file main.c:429 (python.exe:arm64+0x10036fe18)
#14 Py_RunMain main.c:772 (python.exe:arm64+0x10036f24c)
#15 pymain_main main.c:802 (python.exe:arm64+0x10036f6b8)
#16 Py_BytesMain main.c:826 (python.exe:arm64+0x10036f78c)
#17 main python.c:15 (python.exe:arm64+0x1000009b4)
SUMMARY: ThreadSanitizer: data race object.c:3296 in PyRefTracer_SetTracer
==================
==================
WARNING: ThreadSanitizer: data race (pid=77186)
Write of size 4 at 0x000104afd600 by thread T2:
#0 _PyTraceMalloc_Start tracemalloc.c:803 (python.exe:arm64+0x10035b97c)
#1 _tracemalloc_start _tracemalloc.c.h:111 (python.exe:arm64+0x100390244)
#2 cfunction_vectorcall_FASTCALL methodobject.c:449 (python.exe:arm64+0x10011eee8)
#3 _PyObject_Call call.c:348 (python.exe:arm64+0x10007f1cc)
#4 PyObject_Call call.c:373 (python.exe:arm64+0x10007f240)
#5 _PyEval_EvalFrameDefault generated_cases.c.h:2656 (python.exe:arm64+0x10027b0f0)
#6 _PyEval_Vector ceval.c:1977 (python.exe:arm64+0x10026a10c)
#7 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007f554)
#8 method_vectorcall classobject.c:73 (python.exe:arm64+0x100083a94)
#9 context_run context.c:728 (python.exe:arm64+0x1002b4c3c)
#10 method_vectorcall_FASTCALL_KEYWORDS descrobject.c:421 (python.exe:arm64+0x1000963e8)
#11 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x10007ef1c)
#12 _PyEval_EvalFrameDefault generated_cases.c.h:1620 (python.exe:arm64+0x100276ee8)
#13 _PyEval_Vector ceval.c:1977 (python.exe:arm64+0x10026a10c)
#14 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007f554)
#15 method_vectorcall classobject.c:73 (python.exe:arm64+0x100083a94)
#16 _PyObject_Call call.c:348 (python.exe:arm64+0x10007f1cc)
#17 PyObject_Call call.c:373 (python.exe:arm64+0x10007f240)
#18 thread_run _threadmodule.c:373 (python.exe:arm64+0x1003ee358)
#19 pythread_wrapper thread_pthread.h:232 (python.exe:arm64+0x100356ff8)
Previous write of size 4 at 0x000104afd600 by thread T1:
#0 _PyTraceMalloc_Start tracemalloc.c:803 (python.exe:arm64+0x10035b97c)
#1 _tracemalloc_start _tracemalloc.c.h:111 (python.exe:arm64+0x100390244)
#2 cfunction_vectorcall_FASTCALL methodobject.c:449 (python.exe:arm64+0x10011eee8)
#3 _PyObject_Call call.c:348 (python.exe:arm64+0x10007f1cc)
#4 PyObject_Call call.c:373 (python.exe:arm64+0x10007f240)
#5 _PyEval_EvalFrameDefault generated_cases.c.h:2656 (python.exe:arm64+0x10027b0f0)
#6 _PyEval_Vector ceval.c:1977 (python.exe:arm64+0x10026a10c)
#7 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007f554)
#8 method_vectorcall classobject.c:73 (python.exe:arm64+0x100083a94)
#9 context_run context.c:728 (python.exe:arm64+0x1002b4c3c)
#10 method_vectorcall_FASTCALL_KEYWORDS descrobject.c:421 (python.exe:arm64+0x1000963e8)
#11 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x10007ef1c)
#12 _PyEval_EvalFrameDefault generated_cases.c.h:1620 (python.exe:arm64+0x100276ee8)
#13 _PyEval_Vector ceval.c:1977 (python.exe:arm64+0x10026a10c)
#14 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007f554)
#15 method_vectorcall classobject.c:73 (python.exe:arm64+0x100083a94)
#16 _PyObject_Call call.c:348 (python.exe:arm64+0x10007f1cc)
#17 PyObject_Call call.c:373 (python.exe:arm64+0x10007f240)
#18 thread_run _threadmodule.c:373 (python.exe:arm64+0x1003ee358)
#19 pythread_wrapper thread_pthread.h:232 (python.exe:arm64+0x100356ff8)
Location is global '_PyRuntime' at 0x000104afb040 (python.exe+0x100641600)
Thread T2 (tid=421141, running) created by main thread at:
#0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x32b00)
#1 do_start_joinable_thread thread_pthread.h:279 (python.exe:arm64+0x100356250)
#2 PyThread_start_joinable_thread thread_pthread.h:321 (python.exe:arm64+0x100356098)
#3 do_start_new_thread _threadmodule.c:1877 (python.exe:arm64+0x1003edf0c)
#4 thread_PyThread_start_joinable_thread _threadmodule.c:1992 (python.exe:arm64+0x1003ecc9c)
#5 cfunction_call methodobject.c:564 (python.exe:arm64+0x10011fc44)
#6 _PyObject_MakeTpCall call.c:242 (python.exe:arm64+0x10007e3cc)
#7 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x10007efb8)
#8 _PyEval_EvalFrameDefault generated_cases.c.h:3236 (python.exe:arm64+0x10027a5bc)
#9 PyEval_EvalCode ceval.c:868 (python.exe:arm64+0x100269ce8)
#10 run_mod pythonrun.c:1436 (python.exe:arm64+0x100335258)
#11 _PyRun_SimpleFileObject pythonrun.c:521 (python.exe:arm64+0x100330a84)
#12 _PyRun_AnyFileObject pythonrun.c:81 (python.exe:arm64+0x1003301dc)
#13 pymain_run_file main.c:429 (python.exe:arm64+0x10036fe18)
#14 Py_RunMain main.c:772 (python.exe:arm64+0x10036f24c)
#15 pymain_main main.c:802 (python.exe:arm64+0x10036f6b8)
#16 Py_BytesMain main.c:826 (python.exe:arm64+0x10036f78c)
#17 main python.c:15 (python.exe:arm64+0x1000009b4)
Thread T1 (tid=421140, running) created by main thread at:
#0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x32b00)
#1 do_start_joinable_thread thread_pthread.h:279 (python.exe:arm64+0x100356250)
#2 PyThread_start_joinable_thread thread_pthread.h:321 (python.exe:arm64+0x100356098)
#3 do_start_new_thread _threadmodule.c:1877 (python.exe:arm64+0x1003edf0c)
#4 thread_PyThread_start_joinable_thread _threadmodule.c:1992 (python.exe:arm64+0x1003ecc9c)
#5 cfunction_call methodobject.c:564 (python.exe:arm64+0x10011fc44)
#6 _PyObject_MakeTpCall call.c:242 (python.exe:arm64+0x10007e3cc)
#7 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x10007efb8)
#8 _PyEval_EvalFrameDefault generated_cases.c.h:2968 (python.exe:arm64+0x10027c190)
#9 PyEval_EvalCode ceval.c:868 (python.exe:arm64+0x100269ce8)
#10 run_mod pythonrun.c:1436 (python.exe:arm64+0x100335258)
#11 _PyRun_SimpleFileObject pythonrun.c:521 (python.exe:arm64+0x100330a84)
#12 _PyRun_AnyFileObject pythonrun.c:81 (python.exe:arm64+0x1003301dc)
#13 pymain_run_file main.c:429 (python.exe:arm64+0x10036fe18)
#14 Py_RunMain main.c:772 (python.exe:arm64+0x10036f24c)
#15 pymain_main main.c:802 (python.exe:arm64+0x10036f6b8)
#16 Py_BytesMain main.c:826 (python.exe:arm64+0x10036f78c)
#17 main python.c:15 (python.exe:arm64+0x1000009b4)
SUMMARY: ThreadSanitizer: data race tracemalloc.c:803 in _PyTraceMalloc_Start
==================
==================
WARNING: ThreadSanitizer: data race (pid=77186)
Read of size 8 at 0x000104afd6f0 by main thread:
#0 _Py_NewReference object.c:2666 (python.exe:arm64+0x10012efe8)
#1 _PyTuple_FromStackRefStealOnSuccess tupleobject.c:394 (python.exe:arm64+0x100170f20)
#2 _PyEvalFramePushAndInit ceval.c:1847 (python.exe:arm64+0x100286a6c)
#3 _PyEval_EvalFrameDefault generated_cases.c.h:4330 (python.exe:arm64+0x100280f60)
#4 PyEval_EvalCode ceval.c:868 (python.exe:arm64+0x100269ce8)
#5 run_mod pythonrun.c:1436 (python.exe:arm64+0x100335258)
#6 _PyRun_SimpleFileObject pythonrun.c:521 (python.exe:arm64+0x100330a84)
#7 _PyRun_AnyFileObject pythonrun.c:81 (python.exe:arm64+0x1003301dc)
#8 pymain_run_file main.c:429 (python.exe:arm64+0x10036fe18)
#9 Py_RunMain main.c:772 (python.exe:arm64+0x10036f24c)
#10 pymain_main main.c:802 (python.exe:arm64+0x10036f6b8)
#11 Py_BytesMain main.c:826 (python.exe:arm64+0x10036f78c)
#12 main python.c:15 (python.exe:arm64+0x1000009b4)
Previous write of size 8 at 0x000104afd6f0 by thread T1:
#0 PyRefTracer_SetTracer object.c:3297 (python.exe:arm64+0x10012fd9c)
#1 _PyTraceMalloc_Start tracemalloc.c:837 (python.exe:arm64+0x10035ba9c)
#2 _tracemalloc_start _tracemalloc.c.h:111 (python.exe:arm64+0x100390244)
#3 cfunction_vectorcall_FASTCALL methodobject.c:449 (python.exe:arm64+0x10011eee8)
#4 _PyObject_Call call.c:348 (python.exe:arm64+0x10007f1cc)
#5 PyObject_Call call.c:373 (python.exe:arm64+0x10007f240)
#6 _PyEval_EvalFrameDefault generated_cases.c.h:2656 (python.exe:arm64+0x10027b0f0)
#7 _PyEval_Vector ceval.c:1977 (python.exe:arm64+0x10026a10c)
#8 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007f554)
#9 method_vectorcall classobject.c:73 (python.exe:arm64+0x100083a94)
#10 context_run context.c:728 (python.exe:arm64+0x1002b4c3c)
#11 method_vectorcall_FASTCALL_KEYWORDS descrobject.c:421 (python.exe:arm64+0x1000963e8)
#12 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x10007ef1c)
#13 _PyEval_EvalFrameDefault generated_cases.c.h:1620 (python.exe:arm64+0x100276ee8)
#14 _PyEval_Vector ceval.c:1977 (python.exe:arm64+0x10026a10c)
#15 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007f554)
#16 method_vectorcall classobject.c:73 (python.exe:arm64+0x100083a94)
#17 _PyObject_Call call.c:348 (python.exe:arm64+0x10007f1cc)
#18 PyObject_Call call.c:373 (python.exe:arm64+0x10007f240)
#19 thread_run _threadmodule.c:373 (python.exe:arm64+0x1003ee358)
#20 pythread_wrapper thread_pthread.h:232 (python.exe:arm64+0x100356ff8)
Location is global '_PyRuntime' at 0x000104afb040 (python.exe+0x1006416f0)
Thread T1 (tid=421140, running) created by main thread at:
#0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x32b00)
#1 do_start_joinable_thread thread_pthread.h:279 (python.exe:arm64+0x100356250)
#2 PyThread_start_joinable_thread thread_pthread.h:321 (python.exe:arm64+0x100356098)
#3 do_start_new_thread _threadmodule.c:1877 (python.exe:arm64+0x1003edf0c)
#4 thread_PyThread_start_joinable_thread _threadmodule.c:1992 (python.exe:arm64+0x1003ecc9c)
#5 cfunction_call methodobject.c:564 (python.exe:arm64+0x10011fc44)
#6 _PyObject_MakeTpCall call.c:242 (python.exe:arm64+0x10007e3cc)
#7 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x10007efb8)
#8 _PyEval_EvalFrameDefault generated_cases.c.h:2968 (python.exe:arm64+0x10027c190)
#9 PyEval_EvalCode ceval.c:868 (python.exe:arm64+0x100269ce8)
#10 run_mod pythonrun.c:1436 (python.exe:arm64+0x100335258)
#11 _PyRun_SimpleFileObject pythonrun.c:521 (python.exe:arm64+0x100330a84)
#12 _PyRun_AnyFileObject pythonrun.c:81 (python.exe:arm64+0x1003301dc)
#13 pymain_run_file main.c:429 (python.exe:arm64+0x10036fe18)
#14 Py_RunMain main.c:772 (python.exe:arm64+0x10036f24c)
#15 pymain_main main.c:802 (python.exe:arm64+0x10036f6b8)
#16 Py_BytesMain main.c:826 (python.exe:arm64+0x10036f78c)
#17 main python.c:15 (python.exe:arm64+0x1000009b4)
SUMMARY: ThreadSanitizer: data race object.c:2666 in _Py_NewReference
==================
==================
WARNING: ThreadSanitizer: data race (pid=77186)
Write of size 8 at 0x000104afd6a0 by thread T2:
#0 _PyTraceMalloc_Start tracemalloc.c:808 (python.exe:arm64+0x10035b9c4)
#1 _tracemalloc_start _tracemalloc.c.h:111 (python.exe:arm64+0x100390244)
#2 cfunction_vectorcall_FASTCALL methodobject.c:449 (python.exe:arm64+0x10011eee8)
#3 _PyObject_Call call.c:348 (python.exe:arm64+0x10007f1cc)
#4 PyObject_Call call.c:373 (python.exe:arm64+0x10007f240)
#5 _PyEval_EvalFrameDefault generated_cases.c.h:2656 (python.exe:arm64+0x10027b0f0)
#6 _PyEval_Vector ceval.c:1977 (python.exe:arm64+0x10026a10c)
#7 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007f554)
#8 method_vectorcall classobject.c:73 (python.exe:arm64+0x100083a94)
#9 context_run context.c:728 (python.exe:arm64+0x1002b4c3c)
#10 method_vectorcall_FASTCALL_KEYWORDS descrobject.c:421 (python.exe:arm64+0x1000963e8)
#11 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x10007ef1c)
#12 _PyEval_EvalFrameDefault generated_cases.c.h:1620 (python.exe:arm64+0x100276ee8)
#13 _PyEval_Vector ceval.c:1977 (python.exe:arm64+0x10026a10c)
#14 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007f554)
#15 method_vectorcall classobject.c:73 (python.exe:arm64+0x100083a94)
#16 _PyObject_Call call.c:348 (python.exe:arm64+0x10007f1cc)
#17 PyObject_Call call.c:373 (python.exe:arm64+0x10007f240)
#18 thread_run _threadmodule.c:373 (python.exe:arm64+0x1003ee358)
#19 pythread_wrapper thread_pthread.h:232 (python.exe:arm64+0x100356ff8)
Previous write of size 8 at 0x000104afd6a0 by thread T1:
#0 _PyTraceMalloc_Start tracemalloc.c:808 (python.exe:arm64+0x10035b9c4)
#1 _tracemalloc_start _tracemalloc.c.h:111 (python.exe:arm64+0x100390244)
#2 cfunction_vectorcall_FASTCALL methodobject.c:449 (python.exe:arm64+0x10011eee8)
#3 _PyObject_Call call.c:348 (python.exe:arm64+0x10007f1cc)
#4 PyObject_Call call.c:373 (python.exe:arm64+0x10007f240)
#5 _PyEval_EvalFrameDefault generated_cases.c.h:2656 (python.exe:arm64+0x10027b0f0)
#6 _PyEval_Vector ceval.c:1977 (python.exe:arm64+0x10026a10c)
#7 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007f554)
#8 method_vectorcall classobject.c:73 (python.exe:arm64+0x100083a94)
#9 context_run context.c:728 (python.exe:arm64+0x1002b4c3c)
#10 method_vectorcall_FASTCALL_KEYWORDS descrobject.c:421 (python.exe:arm64+0x1000963e8)
#11 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x10007ef1c)
#12 _PyEval_EvalFrameDefault generated_cases.c.h:1620 (python.exe:arm64+0x100276ee8)
#13 _PyEval_Vector ceval.c:1977 (python.exe:arm64+0x10026a10c)
#14 _PyFunction_Vectorcall call.c (python.exe:arm64+0x10007f554)
#15 method_vectorcall classobject.c:73 (python.exe:arm64+0x100083a94)
#16 _PyObject_Call call.c:348 (python.exe:arm64+0x10007f1cc)
#17 PyObject_Call call.c:373 (python.exe:arm64+0x10007f240)
#18 thread_run _threadmodule.c:373 (python.exe:arm64+0x1003ee358)
#19 pythread_wrapper thread_pthread.h:232 (python.exe:arm64+0x100356ff8)
Location is global '_PyRuntime' at 0x000104afb040 (python.exe+0x1006416a0)
Thread T2 (tid=421141, running) created by main thread at:
#0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x32b00)
#1 do_start_joinable_thread thread_pthread.h:279 (python.exe:arm64+0x100356250)
#2 PyThread_start_joinable_thread thread_pthread.h:321 (python.exe:arm64+0x100356098)
#3 do_start_new_thread _threadmodule.c:1877 (python.exe:arm64+0x1003edf0c)
#4 thread_PyThread_start_joinable_thread _threadmodule.c:1992 (python.exe:arm64+0x1003ecc9c)
#5 cfunction_call methodobject.c:564 (python.exe:arm64+0x10011fc44)
#6 _PyObject_MakeTpCall call.c:242 (python.exe:arm64+0x10007e3cc)
#7 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x10007efb8)
#8 _PyEval_EvalFrameDefault generated_cases.c.h:3236 (python.exe:arm64+0x10027a5bc)
#9 PyEval_EvalCode ceval.c:868 (python.exe:arm64+0x100269ce8)
#10 run_mod pythonrun.c:1436 (python.exe:arm64+0x100335258)
#11 _PyRun_SimpleFileObject pythonrun.c:521 (python.exe:arm64+0x100330a84)
#12 _PyRun_AnyFileObject pythonrun.c:81 (python.exe:arm64+0x1003301dc)
#13 pymain_run_file main.c:429 (python.exe:arm64+0x10036fe18)
#14 Py_RunMain main.c:772 (python.exe:arm64+0x10036f24c)
#15 pymain_main main.c:802 (python.exe:arm64+0x10036f6b8)
#16 Py_BytesMain main.c:826 (python.exe:arm64+0x10036f78c)
#17 main python.c:15 (python.exe:arm64+0x1000009b4)
Thread T1 (tid=421140, running) created by main thread at:
#0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x32b00)
#1 do_start_joinable_thread thread_pthread.h:279 (python.exe:arm64+0x100356250)
#2 PyThread_start_joinable_thread thread_pthread.h:321 (python.exe:arm64+0x100356098)
#3 do_start_new_thread _threadmodule.c:1877 (python.exe:arm64+0x1003edf0c)
#4 thread_PyThread_start_joinable_thread _threadmodule.c:1992 (python.exe:arm64+0x1003ecc9c)
#5 cfunction_call methodobject.c:564 (python.exe:arm64+0x10011fc44)
#6 _PyObject_MakeTpCall call.c:242 (python.exe:arm64+0x10007e3cc)
#7 PyObject_Vectorcall call.c:327 (python.exe:arm64+0x10007efb8)
#8 _PyEval_EvalFrameDefault generated_cases.c.h:2968 (python.exe:arm64+0x10027c190)
#9 PyEval_EvalCode ceval.c:868 (python.exe:arm64+0x100269ce8)
#10 run_mod pythonrun.c:1436 (python.exe:arm64+0x100335258)
#11 _PyRun_SimpleFileObject pythonrun.c:521 (python.exe:arm64+0x100330a84)
#12 _PyRun_AnyFileObject pythonrun.c:81 (python.exe:arm64+0x1003301dc)
#13 pymain_run_file main.c:429 (python.exe:arm64+0x10036fe18)
#14 Py_RunMain main.c:772 (python.exe:arm64+0x10036f24c)
#15 pymain_main main.c:802 (python.exe:arm64+0x10036f6b8)
#16 Py_BytesMain main.c:826 (python.exe:arm64+0x10036f78c)
#17 main python.c:15 (python.exe:arm64+0x1000009b4)
SUMMARY: ThreadSanitizer: data race tracemalloc.c:808 in _PyTraceMalloc_Start
==================
colesbury commented on Nov 25, 2025 Reacted by Victor Stinner devdanzin commented on Apr 15, 2026 Reopening: I believe this issue might have been closed prematurely. The tracemalloc.start() concurrent-call assertion failure still reproduces on 3.15 main with gh-137992 merged, because that fix only stops the world around PyRefTracer_SetTracer, not the broader init sequence inside _PyTraceMalloc_Start.
MRE
import os, signal, threading, tracemalloc
def toggler():
for _ in range(500):
try:
tracemalloc.start()
tracemalloc.stop()
except Exception:
pass
pid = os.fork()
if pid == 0:
threads = [threading.Thread(target=toggler) for _ in range(2)]
for t in threads: t.start()
for t in threads: t.join()
os._exit(0)
_, status = os.waitpid(pid, 0)
print(f"CRASH: {signal.Signals(os.WTERMSIG(status)).name}"
if os.WIFSIGNALED(status) else "OK")
Run with:
PYTHON_GIL=0 ./python minimal_repro.py
Result on 3.15.0a7+ (heads/main:4d0e8ee649c, Mar 29 2026)
This build is a free-threading + ASAN + --with-pydebug build of CPython main and does contain the gh-137992 fix — I verified the presence of _PyEval_StopTheWorldAll(&_PyRuntime) in PyRefTracer_SetTracer before running.
python: Python/tracemalloc.c:824: int _PyTraceMalloc_Start(int):
Assertion `tracemalloc_traceback == NULL' failed.
CRASH: SIGABRT
Also reproduces on a 3.14 free-threading + TSan + debug build (where the assertion is at line 814 in the older code), but that build doesn't have the gh-137992 fix, so it's not the interesting data point.
Why the gh-137992 fix doesn't cover this
Looking at _PyTraceMalloc_Start on main:
int
_PyTraceMalloc_Start(int max_nframe)
{
if (max_nframe < 1 || max_nframe > MAX_NFRAME) { ... }
if (_PyTraceMalloc_IsTracing()) {
/* hooks already installed: do nothing */
return 0; // <-- atomic check, but no lock held
}
tracemalloc_config.max_nframe = max_nframe;
size_t size = TRACEBACK_SIZE(max_nframe);
assert(tracemalloc_traceback == NULL); // <-- this fires
tracemalloc_traceback = raw_malloc(size);
// ... more unprotected init ...
if (PyRefTracer_SetTracer(_PyTraceMalloc_TraceRef, NULL) < 0) { ... }
/* everything is ready: start tracing Python memory allocations */
TABLES_LOCK();
_Py_atomic_store_int_relaxed(&tracemalloc_config.tracing, 1); // <-- publication
TABLES_UNLOCK();
return 0;
}
Between the atomic check at _PyTraceMalloc_IsTracing() and the atomic store of tracing=1 under TABLES_LOCK(), the init block is unprotected:
- Thread A calls
tracemalloc.start(), observes tracing == 0, begins init.
- Thread B calls
tracemalloc.start(), also observes tracing == 0 (A hasn't published yet), begins init.
- A completes
tracemalloc_traceback = raw_malloc(...).
- B reaches
assert(tracemalloc_traceback == NULL) → SIGABRT.
The STW fix to PyRefTracer_SetTracer (gh-137994) doesn't help because the assertion fires several statements before that call. What was fixed is the later window where two threads concurrently write _PyRuntime.ref_tracer.tracer_func / .tracer_data — that's a different race, and it's genuinely fixed.
What would close this
Serializing the whole init sequence, probably by taking TABLES_LOCK() at the start of _PyTraceMalloc_Start before the _PyTraceMalloc_IsTracing() re-check (double-checked-locking style), and holding it until the publication at the end. _PyTraceMalloc_Stop already takes TABLES_LOCK() for its whole teardown, so this would just mirror that shape.
I'm not sure what the right venue is. Happy to leave this for you to decide between keeping this issue open, filing a new one, or closing as a known tradeoff. Just wanted to make sure the evidence was on record in case the premature closure was an oversight.
Root cause analysis, reproducer and comment draft done with assistance from Claude Code, reviewed by a human. thalesmourabh commented on Nov 6, 2026 Independent confirmation on current main, plus one addition.
Still reproduces on 3.16. devdanzin's MRE aborts for me on main at
534605904dfa7db25bf19a1b959411b8562c2b80, 3 out of 3 runs:
python: Python/tracemalloc.c:871: _PyTraceMalloc_Start: Assertion `tracemalloc_traceback == NULL' failed.
CRASH: SIGABRT
The same script on a GIL-enabled build of the same commit prints OK.
Two details that differ from the report above, and that I think make the data point worth adding: this is a plain --disable-gil --with-pydebug build with no sanitizer, and it is 3.16, not 3.15. So the abort does not depend on ASan or on that branch. The assertion has moved from line 824 to line 871. I verified _PyEval_StopTheWorldAll(&_PyRuntime) is present in PyRefTracer_SetTracer (Objects/object.c:3455), so gh-137992 is in the tree.
Addition: the unprotected window is wider than the assertion. Between the unlocked _PyTraceMalloc_IsTracing() check and the publication under TABLES_LOCK(), there are also three PyMem_SetAllocator calls:
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc);
PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc);
PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc);
Removing or weakening the assertion would therefore not be sufficient — the allocator swap stays racy. This also appears to be the same window @kumaraditya303 described on 2025-07-08 in this thread ("it changes the allocator used by runtime while other threads could be allocating memory"). The 2025 observation and the 2026 analysis look like one defect seen from two angles, which may matter for scoping a fix.
Reproduction and analysis done with assistance from Claude Code, reviewed by a human.
MetadataMetadataStatusShow more project fields
DevelopmentNo branches or pull requestsIssue actions
|