Bug description:
With free-threading, it is possible to read di->di_dict, while it is being written.
| staticPyObject* |
| dictiter_iternextkey(PyObject*self) |
| { |
| dictiterobject*di= (dictiterobject*)self; |
| PyDictObject*d=di->di_dict; |
| di->di_pos=i+1; |
| di->len--; |
| if (out_key!=NULL) { |
| *out_key=Py_NewRef(key); |
| } |
| if (out_value!=NULL) { |
| *out_value=Py_NewRef(value); |
| } |
| return0; |
| |
| fail: |
| di->di_dict=NULL; |
| Py_DECREF(d); |
| return-1; |
| } |
Reproducer:
importthreadingd= {str(i): iforiinrange(1000)}
it=iter(d)
barrier=threading.Barrier(2)
defrun():
barrier.wait()
for_inrange(10000):
try:
next(it)
exceptStopIteration:
passt1=threading.Thread(target=run)
t2=threading.Thread(target=run)
t1.start()
t2.start()
t1.join()
t2.join()TSAN report:
WARNING: ThreadSanitizer: data race (pid=2919507)
Write of size 8 at 0x7fffb66d6bf0 by thread T2:
#0 dictiter_iternextitem_lock_held /cpython/Objects/dictobject.c:5859:17 (python3.15t+0x2ada61) #1 dictiter_iternext_threadsafe /cpython/Objects/dictobject.c:5995:11 (python3.15t+0x2ada61)
#2 dictiter_iternextkey /cpython/Objects/dictobject.c:5622:9 (python3.15t+0x2a2211) #3 builtin_next /cpython/Python/bltinmodule.c:1764:11 (python3.15t+0x423b62) #4 _Py_BuiltinCallFast_StackRef /cpython/Python/ceval.c:824:11 (python3.15t+0x43223d) #5 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:2409:35 (python3.15t+0x43223d)
#6 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:118:16 (python3.15t+0x429900) #7 _PyEval_Vector /cpython/Python/ceval.c:2124:12 (python3.15t+0x429900)
#8 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.15t+0x21131f) #9 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.15t+0x212e59) #10 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.15t+0x212e59)
#11 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.15t+0x21638f) #12 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.15t+0x481401) #13 context_run /cpython/Python/context.c:727:29 (python3.15t+0x481401)
#14 method_vectorcall_FASTCALL_KEYWORDS /cpython/Objects/descrobject.c:421:24 (python3.15t+0x22b067) #15 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.15t+0x210ca3) #16 PyObject_Vectorcall /cpython/Objects/call.c:327:12 (python3.15t+0x210ca3)
#17 _Py_VectorCallInstrumentation_StackRefSteal /cpython/Python/ceval.c:775:11 (python3.15t+0x42a52c) #18 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:1846:35 (python3.15t+0x43031e) #19 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:118:16 (python3.15t+0x429900) #20 _PyEval_Vector /cpython/Python/ceval.c:2124:12 (python3.15t+0x429900)
#21 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.15t+0x21131f) #22 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.15t+0x212e59) #23 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.15t+0x212e59)
#24 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.15t+0x21638f) #25 _PyVectorcall_Call /cpython/Objects/call.c:273:16 (python3.15t+0x210fab) #26 _PyObject_Call /cpython/Objects/call.c:348:16 (python3.15t+0x210fab)
#27 PyObject_Call /cpython/Objects/call.c:373:12 (python3.15t+0x211015) #28 thread_run /cpython/./Modules/_threadmodule.c:388:21 (python3.15t+0x606be2) #29 pythread_wrapper /cpython/Python/thread_pthread.h:234:5 (python3.15t+0x536447) Previous read of size 8 at 0x7fffb66d6bf0 by thread T1:
#0 dictiter_iternextkey /cpython/Objects/dictobject.c:5615:27 (python3.15t+0x2a21f9) #1 builtin_next /cpython/Python/bltinmodule.c:1764:11 (python3.15t+0x423b62) #2 _Py_BuiltinCallFast_StackRef /cpython/Python/ceval.c:824:11 (python3.15t+0x43223d) #3 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:2409:35 (python3.15t+0x43223d)
#4 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:118:16 (python3.15t+0x429900) #5 _PyEval_Vector /cpython/Python/ceval.c:2124:12 (python3.15t+0x429900)
#6 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.15t+0x21131f) #7 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.15t+0x212e59) #8 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.15t+0x212e59)
#9 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.15t+0x21638f) #10 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.15t+0x481401) #11 context_run /cpython/Python/context.c:727:29 (python3.15t+0x481401)
#12 method_vectorcall_FASTCALL_KEYWORDS /cpython/Objects/descrobject.c:421:24 (python3.15t+0x22b067) #13 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.15t+0x210ca3) #14 PyObject_Vectorcall /cpython/Objects/call.c:327:12 (python3.15t+0x210ca3)
#15 _Py_VectorCallInstrumentation_StackRefSteal /cpython/Python/ceval.c:775:11 (python3.15t+0x42a52c) #16 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:1846:35 (python3.15t+0x43031e) #17 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:118:16 (python3.15t+0x429900) #18 _PyEval_Vector /cpython/Python/ceval.c:2124:12 (python3.15t+0x429900)
#19 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.15t+0x21131f) #20 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.15t+0x212e59) #21 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.15t+0x212e59)
#22 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.15t+0x21638f) #23 _PyVectorcall_Call /cpython/Objects/call.c:273:16 (python3.15t+0x210fab) #24 _PyObject_Call /cpython/Objects/call.c:348:16 (python3.15t+0x210fab)
#25 PyObject_Call /cpython/Objects/call.c:373:12 (python3.15t+0x211015) #26 thread_run /cpython/./Modules/_threadmodule.c:388:21 (python3.15t+0x606be2) #27 pythread_wrapper /cpython/Python/thread_pthread.h:234:5 (python3.15t+0x536447)
CPython versions tested on:
Python 3.15.0a8+ free-threading build (heads/main:f93834ff011, Apr 22 2026, 11:41:06)
Operating systems tested on:
Linux
Bug description:
With free-threading, it is possible to read
di->di_dict, while it is being written.cpython/Objects/dictobject.c
Lines 5611 to 5615 in f93834f
cpython/Objects/dictobject.c
Lines 5848 to 5862 in f93834f
Reproducer:
TSAN report:
CPython versions tested on:
Python 3.15.0a8+ free-threading build (heads/main:f93834ff011, Apr 22 2026, 11:41:06)
Operating systems tested on:
Linux