Repository navigation
Data race between _PyObject_TryGetInstanceAttribute and clear_inline_values #160496
Copy link
Copy link
Open
Labels
topic-free-threadingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Description
Bug report
_PyObject_TryGetInstanceAttribute reads inline values atomically:
Lines 7678 to 7680 in 7715c92
| #ifdef Py_GIL_DISABLED | |
| PyObject *value = _Py_atomic_load_ptr_acquire(&values->values[ix]); | |
| if (value == NULL) { |
but clear_inline_values writes it non-atomically:
Lines 7799 to 7808 in 7715c92
| static void | |
| clear_inline_values(PyDictValues *values) | |
| { | |
| if (values->valid) { | |
| FT_ATOMIC_STORE_UINT8(values->valid, 0); | |
| for (Py_ssize_t i = 0; i < values->capacity; i++) { | |
| Py_CLEAR(values->values[i]); | |
| } | |
| } | |
| } |
This popped up while running some free-threading stress tests locally under TSAN:
WARNING: ThreadSanitizer: data race (pid=793176)
Write of size 8 at 0x7f03aa8c0880 by thread T30:
#0 clear_inline_values Objects/dictobject.c:7805:13
#1 set_dict_inline_values Objects/dictobject.c:7820:5
#2 try_set_dict_inline_only_or_other_dict Objects/dictobject.c:7837:9
#3 _PyObject_SetManagedDict Objects/dictobject.c:7912:14
#4 _PyObject_SetDict Objects/typeobject.c:4004:16
#5 subtype_setdict Objects/typeobject.c:4040:12
#6 getset_set Objects/descrobject.c:252:16
#7 _PyObject_GenericSetAttrWithDict Objects/object.c:2063:19
#8 PyObject_GenericSetAttr Objects/object.c:2134:12
#9 PyObject_SetAttr Objects/object.c:1534:15
#10 builtin_setattr_impl Python/bltinmodule.c:1824:9
...
Previous atomic read of size 8 at 0x7f03aa8c0880 by thread T29:
#0 _Py_atomic_load_ptr_acquire ./Include/cpython/pyatomic_gcc.h:557:18
#1 _PyObject_TryGetInstanceAttribute Objects/dictobject.c:7679:23
#2 _PyObject_GenericGetAttrWithDict Objects/object.c:1951:17
#3 PyObject_GenericGetAttr Objects/object.c:2026:12
#4 _PyObject_GetAttrStackRef Objects/object.c:1370:18
#5 _PyEval_EvalFrameDefault Python/generated_cases.c.h:8771:28
...
I think this is benign from a correctness perspective, but we should use a release store in clear_inline_values.
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
topic-free-threadingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Activity
pythongh-160496: Clear inline values with atomic release stores