Skip to content

Data race between _PyObject_TryGetInstanceAttribute and clear_inline_values #160496

Open

Description

@mpage

Bug report

_PyObject_TryGetInstanceAttribute reads inline values atomically:

cpython/Objects/dictobject.c

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:

cpython/Objects/dictobject.c

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

Activity

  1. self-assigned this
    on Oct 23, 2026
  2. added a commit that references this issue on Oct 23, 2026
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