Bug report
Bug description:
deque_index's clinic input declares stop's default as Py_SIZE(deque),
|
@text_signature "($self, value, [start, [stop]])" |
|
_collections.deque.index as deque_index |
|
|
|
deque: dequeobject |
|
value as v: object |
|
start: object(converter='_PyEval_SliceIndexNotNone', type='Py_ssize_t', c_default='0') = NULL |
|
stop: object(converter='_PyEval_SliceIndexNotNone', type='Py_ssize_t', c_default='Py_SIZE(deque)') = NULL |
|
/ |
|
|
and the generated wrapper reads Py_SIZE(deque) non-atomically before entering the critical_section.
|
static PyObject * |
|
deque_index(PyObject *deque, PyObject *const *args, Py_ssize_t nargs) |
|
{ |
|
PyObject *return_value = NULL; |
|
PyObject *v; |
|
Py_ssize_t start = 0; |
|
Py_ssize_t stop = Py_SIZE(deque); |
Meanwhile mutators (deque_clear, deque_append_lock_held, deque_appendleft_lock_held) update the same field via Py_SET_SIZE.
|
Py_SET_SIZE(deque, Py_SIZE(deque) + 1); |
|
Py_SET_SIZE(deque, Py_SIZE(deque) + 1); |
Reproducer:
import collections
from threading import Thread, Barrier
d = collections.deque(range(100))
N_MUT = 3
ITERS = 10000
barrier = Barrier(1 + N_MUT)
def index_thread():
barrier.wait()
for _ in range(ITERS):
try:
d.index(50)
except ValueError:
pass
def mut_thread():
barrier.wait()
for _ in range(ITERS):
d.append(0)
d.clear()
d.extend(range(100))
d.appendleft(-1)
if __name__ == "__main__":
threads = [Thread(target=index_thread)]
threads += [Thread(target=mut_thread) for _ in range(N_MUT)]
for t in threads: t.start()
for t in threads: t.join()
TSAN Report:
WARNING: ThreadSanitizer: data race (pid=745816)
Read of size 8 at 0x7fffb63e9f20 by thread T1:
#0 deque_index /cpython/./Modules/clinic/_collectionsmodule.c.h:343:23 (python3.16t+0x5bd290)
#1 method_vectorcall_FASTCALL /cpython/Objects/descrobject.c:402:24 (python3.16t+0x22e771)
#2 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x2149a8)
#3 PyObject_Vectorcall /cpython/Objects/call.c:327:12 (python3.16t+0x2149a8)
#4 _Py_VectorCallInstrumentation_StackRefSteal /cpython/Python/ceval.c:766:11 (python3.16t+0x4370c8)
#5 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:1846:35 (python3.16t+0x43d022)
#6 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463)
#7 _PyEval_Vector /cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
#8 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.16t+0x215013)
#9 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11)
#10 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
#11 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132)
#12 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x48ec15)
#13 context_run /cpython/Python/context.c:728:29 (python3.16t+0x48ec15)
#14 method_vectorcall_FASTCALL_KEYWORDS /cpython/Objects/descrobject.c:421:24 (python3.16t+0x22e84c)
#15 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x2149a8)
#16 PyObject_Vectorcall /cpython/Objects/call.c:327:12 (python3.16t+0x2149a8)
#17 _Py_VectorCallInstrumentation_StackRefSteal /cpython/Python/ceval.c:766:11 (python3.16t+0x4370c8)
#18 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:1846:35 (python3.16t+0x43d022)
#19 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463)
#20 _PyEval_Vector /cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
#21 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.16t+0x215013)
#22 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11)
#23 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
#24 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132)
#25 _PyVectorcall_Call /cpython/Objects/call.c:273:16 (python3.16t+0x214ca2)
#26 _PyObject_Call /cpython/Objects/call.c:348:16 (python3.16t+0x214ca2)
#27 PyObject_Call /cpython/Objects/call.c:373:12 (python3.16t+0x214d07)
#28 thread_run /cpython/./Modules/_threadmodule.c:388:21 (python3.16t+0x61a708)
#29 pythread_wrapper /cpython/Python/thread_pthread.h:234:5 (python3.16t+0x5473bb)
Previous atomic write of size 8 at 0x7fffb63e9f20 by thread T2:
#0 _Py_atomic_store_ssize_relaxed /cpython/./Include/cpython/pyatomic_gcc.h:513:3 (python3.16t+0x5bc41e)
#1 _Py_SET_SIZE_impl /cpython/./Include/object.h:258:5 (python3.16t+0x5bc41e)
#2 deque_append_lock_held /cpython/./Modules/_collectionsmodule.c:356:5 (python3.16t+0x5bc41e)
#3 deque_extend_impl /cpython/./Modules/_collectionsmodule.c:514:13 (python3.16t+0x5bbeaf)
#4 deque_extend /cpython/./Modules/clinic/_collectionsmodule.c.h:127:20 (python3.16t+0x5bc29b)
#5 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:4261:35 (python3.16t+0x443538)
#6 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463)
#7 _PyEval_Vector /cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
#8 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.16t+0x215013)
#9 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11)
#10 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
#11 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132)
#12 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x48ec15)
#13 context_run /cpython/Python/context.c:728:29 (python3.16t+0x48ec15)
#14 method_vectorcall_FASTCALL_KEYWORDS /cpython/Objects/descrobject.c:421:24 (python3.16t+0x22e84c)
#15 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x2149a8)
#16 PyObject_Vectorcall /cpython/Objects/call.c:327:12 (python3.16t+0x2149a8)
#17 _Py_VectorCallInstrumentation_StackRefSteal /cpython/Python/ceval.c:766:11 (python3.16t+0x4370c8)
#18 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:1846:35 (python3.16t+0x43d022)
#19 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463)
#20 _PyEval_Vector /cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
#21 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.16t+0x215013)
#22 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11)
#23 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
#24 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132)
#25 _PyVectorcall_Call /cpython/Objects/call.c:273:16 (python3.16t+0x214ca2)
#26 _PyObject_Call /cpython/Objects/call.c:348:16 (python3.16t+0x214ca2)
#27 PyObject_Call /cpython/Objects/call.c:373:12 (python3.16t+0x214d07)
#28 thread_run /cpython/./Modules/_threadmodule.c:388:21 (python3.16t+0x61a708)
#29 pythread_wrapper /cpython/Python/thread_pthread.h:234:5 (python3.16t+0x5473bb)
...
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Bug report
Bug description:
deque_index's clinic input declaresstop's default asPy_SIZE(deque),cpython/Modules/_collectionsmodule.c
Lines 1247 to 1255 in 160dc74
and the generated wrapper reads
Py_SIZE(deque)non-atomically before entering the critical_section.cpython/Modules/clinic/_collectionsmodule.c.h
Lines 337 to 343 in 160dc74
Meanwhile mutators (
deque_clear,deque_append_lock_held,deque_appendleft_lock_held) update the same field viaPy_SET_SIZE.cpython/Modules/_collectionsmodule.c
Line 356 in 160dc74
cpython/Modules/_collectionsmodule.c
Line 405 in 160dc74
cpython/Modules/_collectionsmodule.c
Line 763 in 160dc74
Reproducer:
TSAN Report:
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux