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); |
| Py_SET_SIZE(deque, 0); |
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