Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Data race between deque.index and deque mutators on Py_SIZE with free-threading #150750

Description

@Naserume

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

Linked PRs

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions