Bug description:
With free-threading, it is possible to read di->di_dict, while it is being written.
|
static PyObject* |
|
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); |
|
} |
|
return 0; |
|
|
|
fail: |
|
di->di_dict = NULL; |
|
Py_DECREF(d); |
|
return -1; |
|
} |
Reproducer:
import threading
d = {str(i): i for i in range(1000)}
it = iter(d)
barrier = threading.Barrier(2)
def run():
barrier.wait()
for _ in range(10000):
try:
next(it)
except StopIteration:
pass
t1 = 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