Skip to content

Data races found by TSAN on free-threaded build #4904

@ngoldbaum

Description

@ngoldbaum

I'm running on a mac with clang-19 installed via homebrew. I also have a version of the CPython 3.13 branch compiled in free-threaded mode with TSAN instrumentation. If you use the following cargo build invocation

LDFLAGS="-L/opt/homebrew/opt/llvm/lib" CPPFLAGS="-I/opt/homebrew/opt/llvm/include" RUSTFLAGS="-Zsanitizer=thread" cargo build --all-targets -Zbuild-std --target aarch64-apple-darwin

and then run nox, you'll see some errors reported by TSAN over the course of the tests.

Here is a gist that includes the full nox -s test output: https://gist.github.com/ngoldbaum/b01ea1cd3c6f39fbf2e68938b6489243

Looking through, It looks like almost all are due to uses of Py_CompileString. Apparently Py_CompileString isn't thread-safe. I don't see any upstream issues about that:


test conversions::std::array::tests::array_try_from_fn ... ok
==================
WARNING: ThreadSanitizer: data race (pid=53033)
  Read of size 8 at 0x000103d43f88 by thread T10 (mutexes: write M0):
    #0 bytes_hash bytesobject.c:1588 (libpython3.13t.dylib:arm64+0x74548)
    #1 PyObject_Hash object.c (libpython3.13t.dylib:arm64+0x11e470)
    #2 tuplehash tupleobject.c:328 (libpython3.13t.dylib:arm64+0x163dbc)
    #3 PyObject_Hash object.c (libpython3.13t.dylib:arm64+0x11e470)
    #4 dict_setdefault_ref_lock_held dictobject.c:4228 (libpython3.13t.dylib:arm64+0xf6574)
    #5 PyDict_SetDefaultRef dictobject.c:4332 (libpython3.13t.dylib:arm64+0xf6420)
    #6 _PyCompile_ConstCacheMergeOne compile.c:7606 (libpython3.13t.dylib:arm64+0x274ffc)
    #7 _PyAssemble_MakeCodeObject assemble.c:752 (libpython3.13t.dylib:arm64+0x23d9bc)
    #8 optimize_and_assemble compile.c:7704 (libpython3.13t.dylib:arm64+0x276b38)
    #9 _PyAST_Compile compile.c:451 (libpython3.13t.dylib:arm64+0x27483c)
    #10 Py_CompileStringObject pythonrun.c:1496 (libpython3.13t.dylib:arm64+0x303bbc)
    #11 Py_CompileStringExFlags pythonrun.c:1509 (libpython3.13t.dylib:arm64+0x303c88)
    #12 pyo3_ffi::cpython::pythonrun::Py_CompileString::h15f81e42b5109582 pythonrun.rs:140 (pyo3-ac906cf3b9e6a601:arm64+0x1002aea44)

  Previous write of size 8 at 0x000103d43f88 by thread T4 (mutexes: write M1):
    #0 bytes_hash bytesobject.c:1590 (libpython3.13t.dylib:arm64+0x74574)
    #1 PyObject_Hash object.c (libpython3.13t.dylib:arm64+0x11e470)
    #2 tuplehash tupleobject.c:328 (libpython3.13t.dylib:arm64+0x163dbc)
    #3 PyObject_Hash object.c (libpython3.13t.dylib:arm64+0x11e470)
    #4 dict_setdefault_ref_lock_held dictobject.c:4228 (libpython3.13t.dylib:arm64+0xf6574)
    #5 PyDict_SetDefaultRef dictobject.c:4332 (libpython3.13t.dylib:arm64+0xf6420)
    #6 _PyCompile_ConstCacheMergeOne compile.c:7606 (libpython3.13t.dylib:arm64+0x274ffc)
    #7 _PyAssemble_MakeCodeObject assemble.c:752 (libpython3.13t.dylib:arm64+0x23d9bc)
    #8 optimize_and_assemble compile.c:7704 (libpython3.13t.dylib:arm64+0x276b38)
    #9 _PyAST_Compile compile.c:451 (libpython3.13t.dylib:arm64+0x27483c)
    #10 Py_CompileStringObject pythonrun.c:1496 (libpython3.13t.dylib:arm64+0x303bbc)
    #11 Py_CompileStringExFlags pythonrun.c:1509 (libpython3.13t.dylib:arm64+0x303c88)
    #12 pyo3_ffi::cpython::pythonrun::Py_CompileString::h15f81e42b5109582 pythonrun.rs:140 (pyo3-ac906cf3b9e6a601:arm64+0x1002aea44)

  Location is global '_PyRuntime' at 0x000103d3da80 (libpython3.13t.dylib+0x5e7f88)

These look like races in pyo3 internals:

test pycell::impl_::tests::test_inherited_mutability ... ok
==================
WARNING: ThreadSanitizer: data race (pid=53033)
  Read of size 8 at 0x000300040838 by thread T343 (mutexes: write M0):
    #0 _PyType_AllocNoTrack typeobject.c:2036 (libpython3.13t.dylib:arm64+0x16961c)
    #1 PyType_GenericAlloc typeobject.c:2072 (libpython3.13t.dylib:arm64+0x169588)
    #2 _$LT$pyo3..impl_..pyclass_init..PyNativeTypeInitializer$LT$T$GT$$u20$as$u20$pyo3..impl_..pyclass_init..PyObjectInit$LT$T$GT$$GT$::into_new_object::inner::hdfdf96f099d45698 pyclass_init.rs:52 (pyo3-ac906cf3b9e6a601:arm64+0x1001a2efc)

  Previous write of size 8 at 0x000300040838 by thread T341 (mutexes: write M1):
    #0 type_ready typeobject.c:8219 (libpython3.13t.dylib:arm64+0x1742d4)
    #1 PyType_Ready typeobject.c:8272 (libpython3.13t.dylib:arm64+0x16cef0)
    #2 _PyType_FromMetaclass_impl typeobject.c:4791 (libpython3.13t.dylib:arm64+0x16b3e8)
    #3 PyType_FromSpec typeobject.c:4885 (libpython3.13t.dylib:arm64+0x16b628)
    #4 pyo3::pyclass::create_type_object::PyTypeBuilder::build::h481a95053e080b2c create_type_object.rs:493 (pyo3-ac906cf3b9e6a601:arm64+0x1000bee6c)

SUMMARY: ThreadSanitizer: data race typeobject.c:2036 in _PyType_AllocNoTrack
WARNING: ThreadSanitizer: data race (pid=53249)
  Atomic read of size 8 at 0x00011a040400 by thread T15 (mutexes: write M0):
    #0 _Py_IncRef object.c:341 (libpython3.13t.dylib:arm64+0x11a818)
    #1 pyo3::instance::Py$LT$T$GT$::clone_ref::h2bbb76304febf2d9 <null> (test_proto_methods-a5eae531fea38861:arm64+0x1000b4f28)

  Previous write of size 8 at 0x00011a040400 by thread T14 (mutexes: write M1):
    #0 _Py_NewReference object.c:2483 (libpython3.13t.dylib:arm64+0x123c94)
    #1 _PyType_AllocNoTrack typeobject.c:2061 (libpython3.13t.dylib:arm64+0x169824)
    #2 PyType_GenericAlloc typeobject.c:2072 (libpython3.13t.dylib:arm64+0x169588)
    #3 _PyType_FromMetaclass_impl typeobject.c:4685 (libpython3.13t.dylib:arm64+0x16ae20)
    #4 PyType_FromSpec typeobject.c:4885 (libpython3.13t.dylib:arm64+0x16b628)
    #5 pyo3::pyclass::create_type_object::PyTypeBuilder::build::h066e6d4dea4b3239 <null> (test_proto_methods-a5eae531fea38861:arm64+0x10009a118)

SUMMARY: ThreadSanitizer: data race object.c:341 in _Py_IncRef

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions