Skip to content

Possible data race in dictiter_iternext with with free-threading build #148873

Description

@Naserume

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions