Skip to content

slot.__delete__() behaves as non-atomic in free-threading #146270

Description

@x42005e1f

Bug report

Bug description:

In #119368+#123211, member descriptors (related to user-defined slots) were made thread-safe. But not everywhere. The branch related to deletion remained unchanged:

if (v == NULL) {
if (l->type == Py_T_OBJECT_EX) {
/* Check if the attribute is set. */
if (*(PyObject **)addr == NULL) {
PyErr_SetString(PyExc_AttributeError, l->name);
return -1;
}
}
else if (l->type != _Py_T_OBJECT) {
PyErr_SetString(PyExc_TypeError,
"can't delete numeric/char attribute");
return -1;
}
}

Since threads perform the check (addr == NULL) in a non-thread-safe manner, the operation may succeed even if it has already been executed by another thread. At the Python level, this means that an AttributeError may not be raised during two or more concurrent attempts to delete an attribute, and as a result, code that was supposed to execute only once (after a successful deletion) will be executed more than once.

The behavior matches what is expected on CPython with GIL and on PyPy (and possibly other interpreters), but not on CPython without GIL. Without slots (using __dict__), the behavior also matches what is expected even in free-threading. Meanwhile, user-defined slots already rely on critical sections, so the simplest solution would be to move the check for Py_T_OBJECT_EX under the critical section (into the case block).

Code to reproduce (del obj.b raises an AttributeError):

#!/usr/bin/env python3

import time

from concurrent.futures import ThreadPoolExecutor


class ObjectWithSlots:
    __slots__ = (
        "a",
        "b",
    )

    def __init__(self):
        self.a = None
        self.b = None


def main():
    def test():
        try:
            del obj.a
        except AttributeError:  # not the first thread
            pass
        else:
            del obj.b

    with ThreadPoolExecutor(2) as executor:
        start = time.perf_counter()

        while time.perf_counter() - start < 1:  # one second
            obj = ObjectWithSlots()

            f1 = executor.submit(test)
            f2 = executor.submit(test)

            f1.result()  # reraise
            f2.result()  # reraise


if __name__ == "__main__":
    main()

CPython versions tested on:

3.14

Operating systems tested on:

Linux

Linked PRs

Activity

  1. brijkapadia commented on Mar 22, 2026

    @brijkapadia
    Contributor

    I am not able to reproduce the result (del obj.b does not raise any exception) on main. Doesn't the first thread delete both obj.a and obj.b?

  2. x42005e1f commented on Mar 22, 2026

    @x42005e1f
    ContributorAuthor

    The result is reproduced in free-threading. Below is my output on CPython 3.14.3t (via mise):

    Traceback (most recent call last):
      File "/home/user/workspace/example.py", line 42, in <module>
        main()
        ~~~~^^
      File "/home/user/workspace/example.py", line 38, in main
        f2.result()  # reraise
        ~~~~~~~~~^^
      File "/home/user/.local/share/mise/installs/python/3.14.3t/lib/python3.14t/concurrent/futures/_base.py", line 443, in result
        return self.__get_result()
               ~~~~~~~~~~~~~~~~~^^
      File "/home/user/.local/share/mise/installs/python/3.14.3t/lib/python3.14t/concurrent/futures/_base.py", line 395, in __get_result
        raise self._exception
      File "/home/user/.local/share/mise/installs/python/3.14.3t/lib/python3.14t/concurrent/futures/thread.py", line 86, in run
        result = ctx.run(self.task)
      File "/home/user/.local/share/mise/installs/python/3.14.3t/lib/python3.14t/concurrent/futures/thread.py", line 73, in run
        return fn(*args, **kwargs)
      File "/home/user/workspace/example.py", line 26, in test
        del obj.b
            ^^^^^
    AttributeError: b

    If you cannot reproduce this, you are likely not running in free-threading mode (the successful deletion of both attributes is the expected behavior that should be achieved). Alternatively, other factors may be at play, but it takes me only a fraction of a second to reproduce the issue.


    CPython 3.15.0a7+ free-threading build (heads/main:f0aeabc)
    Traceback (most recent call last):
      File "/home/user/workspace/example.py", line 42, in <module>
        main()
        ~~~~^^
      File "/home/user/workspace/example.py", line 37, in main
        f1.result()  # reraise
        ~~~~~~~~~^^
      File "/home/user/.local/share/mise/installs/python/3.15t-dev/lib/python3.15t/concurrent/futures/_base.py", line 443, in result
        return self.__get_result()
               ~~~~~~~~~~~~~~~~~^^
      File "/home/user/.local/share/mise/installs/python/3.15t-dev/lib/python3.15t/concurrent/futures/_base.py", line 395, in __get_result
        raise self._exception
      File "/home/user/.local/share/mise/installs/python/3.15t-dev/lib/python3.15t/concurrent/futures/thread.py", line 86, in run
        result = ctx.run(self.task)
      File "/home/user/.local/share/mise/installs/python/3.15t-dev/lib/python3.15t/concurrent/futures/thread.py", line 73, in run
        return fn(*args, **kwargs)
      File "/home/user/workspace/example.py", line 26, in test
        del obj.b
            ^^^^^
    AttributeError: b
  3. x42005e1f commented on Mar 22, 2026

    @x42005e1f
    ContributorAuthor

    If you cannot reproduce the issue exactly in free-threading, then it may be due to a difference in the system scheduler. I write my tests specifically based on elapsed time rather than the number of iterations to minimize differences in hardware speed and interpreter implementation (if one machine runs the software twice as fast as another, but both use the same timeslices (e.g., the same 5 milliseconds with GIL), then the first machine’s thread-safety coverage will be twice as bad as the second’s for the same number of iterations; therefore, it seems to me that elapsed time is a much more suitable parameter for reproducibility here, if we ignore the impact of foreign processes). I have a custom scheduler and a laptop from the early 2010s, which may affect reproducibility, since a different scheduler might schedule threads in such a way that two short-term scheduled calls would never actually enter a race condition.

    If that is the case, please let me know so I can try to write a test that takes into account the specifics of your scheduler.


    I just tested it on modern hardware and the default scheduler. Nope, the issue reproduces there too.

  4. brijkapadia commented on Mar 22, 2026

    @brijkapadia
    Contributor

    When I run it on main with this config:
    ./configure --with-pydebug --with-thread-sanitizer --disable-gil,
    I do not getting any error. However, when I downloaded 3.14.3t, I did get an error so there is a chance that this issue has already been fixed.

  5. x42005e1f commented on Mar 23, 2026

    @x42005e1f
    ContributorAuthor

    ./configure --with-pydebug --with-thread-sanitizer --disable-gil

    When you call sys._is_gil_enabled(), do you get False?

    I did get an error so there is a chance that this issue has already been fixed.

    My comment also includes an output for main, commit f0aeabc, where the issue reproduces. The issue has definitely not been fixed, since I can still see it in the source code and can personally reproduce it on main. (The latter is included here purely for illustrative purposes, since thread-safety issues are not always easy to reproduce.)

  6. x42005e1f commented on Mar 23, 2026

    @x42005e1f
    ContributorAuthor

    Behavior that occurs in free-threading:

    1. Suppose both threads have entered PyMember_SetOne().
    2. Thread A checks addr == NULL, gets false, but sleeps before FT_ATOMIC_STORE_PTR_RELEASE().
    3. Thread B also checks addr == NULL and also gets false (since Thread A did not have time to change the value of addr).
    4. The rest of this story is of no interest to us: neither of these threads will raise an AttributeError at del obj.a, and as a result, both threads will attempt to do del obj.b (and either enter a race condition again, or one of them will raise an AttributeError).

    A classic scenario, nothing new. Incorrect sequences such as if not loop.is_closed(): loop.call_soon_threadsafe(...) also have this nature (unfortunately, I sometimes see this in various projects; here it would be better to use a try-except on RuntimeError instead, since otherwise the event loop may close before the call but after the check), and everything else that for some reason tries to use simple checks in a multithreaded environment.

  7. x42005e1f commented on Mar 23, 2026

    @x42005e1f
    ContributorAuthor

    ./configure --with-pydebug --with-thread-sanitizer --disable-gil

    Okay, I built main with your configuration via Docker (reusing the environment from python:latest), and I understood why you could not reproduce the issue (apologies for my tone; I have a specific background in working with people). By process of elimination, I concluded that TSan (--with-thread-sanitizer) is to blame, as it affects the test's behavior so significantly that... Let me put it this way: I ran 10 tests with a timeout of 60 (one minute, see the while loop condition), and only 2 of them were able to reproduce the issue (with the same output). Moreover, TSan printed a warning in only one of the remaining 8 runs.

    output-1&2.txt (reproduced)
    WARNING: ThreadSanitizer: data race (pid=10204)
      Atomic write of size 8 at 0x7ff98015b340 by thread T1:
        #0 _Py_atomic_store_ptr_release Include/cpython/pyatomic_gcc.h:565 (python+0x45c1b4) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #1 PyMember_SetOne Python/structmember.c:335 (python+0x45c1b4)
        #2 member_set Objects/descrobject.c:239 (python+0x1afd6b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #3 _PyObject_GenericSetAttrWithDict Objects/object.c:2047 (python+0x230fc5) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #4 PyObject_GenericSetAttr Objects/object.c:2118 (python+0x2312e8) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #5 PyObject_SetAttr Objects/object.c:1531 (python+0x22ed96) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #6 PyObject_DelAttr Objects/object.c:1567 (python+0x22f08a) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #7 _PyEval_EvalFrameDefault Python/generated_cases.c.h:5377 (python+0x3832de) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #8 _PyEval_EvalFrame Include/internal/pycore_ceval.h:118 (python+0x399f70) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #9 _PyEval_Vector Python/ceval.c:2166 (python+0x39a1ee) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #10 _PyFunction_Vectorcall Objects/call.c:413 (python+0x1982c9) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #11 _PyObject_VectorcallTstate Include/internal/pycore_call.h:144 (python+0x1986f7) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #12 _PyObject_VectorcallPrepend Objects/call.c:855 (python+0x1996a8) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #13 method_vectorcall Objects/classobject.c:55 (python+0x19c88b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #14 _PyObject_VectorcallTstate Include/internal/pycore_call.h:144 (python+0x3c561b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #15 context_run Python/context.c:727 (python+0x3c65f1) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #16 method_vectorcall_FASTCALL_KEYWORDS Objects/descrobject.c:421 (python+0x1b071b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #17 _PyObject_VectorcallTstate Include/internal/pycore_call.h:144 (python+0x1986f7) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #18 PyObject_Vectorcall Objects/call.c:327 (python+0x19883d) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #19 _Py_VectorCallInstrumentation_StackRefSteal Python/ceval.c:775 (python+0x36f1ca) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #20 _PyEval_EvalFrameDefault Python/generated_cases.c.h:1841 (python+0x3790ab) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #21 _PyEval_EvalFrame Include/internal/pycore_ceval.h:118 (python+0x399f70) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #22 _PyEval_Vector Python/ceval.c:2166 (python+0x39a1ee) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #23 _PyFunction_Vectorcall Objects/call.c:413 (python+0x1982c9) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #24 _PyObject_VectorcallTstate Include/internal/pycore_call.h:144 (python+0x1986f7) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #25 _PyObject_VectorcallPrepend Objects/call.c:855 (python+0x1996a8) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #26 method_vectorcall Objects/classobject.c:55 (python+0x19c88b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #27 _PyVectorcall_Call Objects/call.c:273 (python+0x19a661) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #28 _PyObject_Call Objects/call.c:348 (python+0x19a9aa) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #29 PyObject_Call Objects/call.c:373 (python+0x19aa0a) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #30 thread_run Modules/_threadmodule.c:387 (python+0x537b2e) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #31 pythread_wrapper Python/thread_pthread.h:234 (python+0x47255f) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
    
      Previous read of size 8 at 0x7ff98015b340 by thread T2:
        #0 PyMember_SetOne Python/structmember.c:177 (python+0x45baf8) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #1 member_set Objects/descrobject.c:239 (python+0x1afd6b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #2 _PyObject_GenericSetAttrWithDict Objects/object.c:2047 (python+0x230fc5) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #3 PyObject_GenericSetAttr Objects/object.c:2118 (python+0x2312e8) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #4 PyObject_SetAttr Objects/object.c:1531 (python+0x22ed96) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #5 PyObject_DelAttr Objects/object.c:1567 (python+0x22f08a) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #6 _PyEval_EvalFrameDefault Python/generated_cases.c.h:5377 (python+0x3832de) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #7 _PyEval_EvalFrame Include/internal/pycore_ceval.h:118 (python+0x399f70) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #8 _PyEval_Vector Python/ceval.c:2166 (python+0x39a1ee) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #9 _PyFunction_Vectorcall Objects/call.c:413 (python+0x1982c9) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #10 _PyObject_VectorcallTstate Include/internal/pycore_call.h:144 (python+0x1986f7) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #11 _PyObject_VectorcallPrepend Objects/call.c:855 (python+0x1996a8) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #12 method_vectorcall Objects/classobject.c:55 (python+0x19c88b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #13 _PyObject_VectorcallTstate Include/internal/pycore_call.h:144 (python+0x3c561b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #14 context_run Python/context.c:727 (python+0x3c65f1) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #15 method_vectorcall_FASTCALL_KEYWORDS Objects/descrobject.c:421 (python+0x1b071b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #16 _PyObject_VectorcallTstate Include/internal/pycore_call.h:144 (python+0x1986f7) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #17 PyObject_Vectorcall Objects/call.c:327 (python+0x19883d) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #18 _Py_VectorCallInstrumentation_StackRefSteal Python/ceval.c:775 (python+0x36f1ca) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #19 _PyEval_EvalFrameDefault Python/generated_cases.c.h:1841 (python+0x3790ab) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #20 _PyEval_EvalFrame Include/internal/pycore_ceval.h:118 (python+0x399f70) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #21 _PyEval_Vector Python/ceval.c:2166 (python+0x39a1ee) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #22 _PyFunction_Vectorcall Objects/call.c:413 (python+0x1982c9) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #23 _PyObject_VectorcallTstate Include/internal/pycore_call.h:144 (python+0x1986f7) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #24 _PyObject_VectorcallPrepend Objects/call.c:855 (python+0x1996a8) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #25 method_vectorcall Objects/classobject.c:55 (python+0x19c88b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #26 _PyVectorcall_Call Objects/call.c:273 (python+0x19a661) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #27 _PyObject_Call Objects/call.c:348 (python+0x19a9aa) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #28 PyObject_Call Objects/call.c:373 (python+0x19aa0a) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #29 thread_run Modules/_threadmodule.c:387 (python+0x537b2e) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #30 pythread_wrapper Python/thread_pthread.h:234 (python+0x47255f) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
    
      Thread T1 'ThreadPoolExecu' (tid=10206, running) created by main thread at:
        #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1022 (libtsan.so.2+0x568a6) (BuildId: 99ef88596cb10a8ccf307fe1a9070f66a44b1624)
        #1 do_start_joinable_thread Python/thread_pthread.h:281 (python+0x4729c9) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #2 PyThread_start_joinable_thread Python/thread_pthread.h:323 (python+0x472b6d) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #3 ThreadHandle_start Modules/_threadmodule.c:474 (python+0x5374fc) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #4 do_start_new_thread Modules/_threadmodule.c:1920 (python+0x5376fe) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #5 thread_PyThread_start_joinable_thread Modules/_threadmodule.c:2043 (python+0x537959) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #6 cfunction_call Objects/methodobject.c:564 (python+0x223185) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #7 _PyObject_MakeTpCall Objects/call.c:242 (python+0x198521) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #8 _PyObject_VectorcallTstate Include/internal/pycore_call.h:142 (python+0x19878a) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #9 PyObject_Vectorcall Objects/call.c:327 (python+0x19883d) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #10 _Py_VectorCallInstrumentation_StackRefSteal Python/ceval.c:775 (python+0x36f1ca) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #11 _PyEval_EvalFrameDefault Python/generated_cases.c.h:3222 (python+0x37d203) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #12 _PyEval_EvalFrame Include/internal/pycore_ceval.h:118 (python+0x399f70) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #13 _PyEval_Vector Python/ceval.c:2166 (python+0x39a1ee) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #14 PyEval_EvalCode Python/ceval.c:686 (python+0x39a336) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #15 run_eval_code_obj Python/pythonrun.c:1368 (python+0x44ea97) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #16 run_mod Python/pythonrun.c:1471 (python+0x44ed78) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #17 pyrun_file Python/pythonrun.c:1295 (python+0x44f7a1) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #18 _PyRun_SimpleFileObject Python/pythonrun.c:518 (python+0x4515fa) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #19 _PyRun_AnyFileObject Python/pythonrun.c:81 (python+0x4517fc) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #20 pymain_run_file_obj Modules/main.c:410 (python+0x48b858) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #21 pymain_run_file Modules/main.c:429 (python+0x48b9b4) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #22 pymain_run_python Modules/main.c:714 (python+0x48c8fa) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #23 Py_RunMain Modules/main.c:795 (python+0x48cbd2) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #24 pymain_main Modules/main.c:825 (python+0x48cc66) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #25 Py_BytesMain Modules/main.c:849 (python+0x48cd77) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #26 main Programs/python.c:15 (python+0x9abc7) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
    
      Thread T2 'ThreadPoolExecu' (tid=10207, running) created by main thread at:
        #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1022 (libtsan.so.2+0x568a6) (BuildId: 99ef88596cb10a8ccf307fe1a9070f66a44b1624)
        #1 do_start_joinable_thread Python/thread_pthread.h:281 (python+0x4729c9) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #2 PyThread_start_joinable_thread Python/thread_pthread.h:323 (python+0x472b6d) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #3 ThreadHandle_start Modules/_threadmodule.c:474 (python+0x5374fc) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #4 do_start_new_thread Modules/_threadmodule.c:1920 (python+0x5376fe) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #5 thread_PyThread_start_joinable_thread Modules/_threadmodule.c:2043 (python+0x537959) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #6 cfunction_call Objects/methodobject.c:564 (python+0x223185) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #7 _PyObject_MakeTpCall Objects/call.c:242 (python+0x198521) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #8 _PyObject_VectorcallTstate Include/internal/pycore_call.h:142 (python+0x19878a) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #9 PyObject_Vectorcall Objects/call.c:327 (python+0x19883d) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #10 _Py_VectorCall_StackRefSteal Python/ceval.c:733 (python+0x36f06f) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #11 _PyEval_EvalFrameDefault Python/generated_cases.c.h:3424 (python+0x37ddb3) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #12 _PyEval_EvalFrame Include/internal/pycore_ceval.h:118 (python+0x399f70) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #13 _PyEval_Vector Python/ceval.c:2166 (python+0x39a1ee) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #14 PyEval_EvalCode Python/ceval.c:686 (python+0x39a336) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #15 run_eval_code_obj Python/pythonrun.c:1368 (python+0x44ea97) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #16 run_mod Python/pythonrun.c:1471 (python+0x44ed78) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #17 pyrun_file Python/pythonrun.c:1295 (python+0x44f7a1) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #18 _PyRun_SimpleFileObject Python/pythonrun.c:518 (python+0x4515fa) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #19 _PyRun_AnyFileObject Python/pythonrun.c:81 (python+0x4517fc) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #20 pymain_run_file_obj Modules/main.c:410 (python+0x48b858) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #21 pymain_run_file Modules/main.c:429 (python+0x48b9b4) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #22 pymain_run_python Modules/main.c:714 (python+0x48c8fa) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #23 Py_RunMain Modules/main.c:795 (python+0x48cbd2) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #24 pymain_main Modules/main.c:825 (python+0x48cc66) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #25 Py_BytesMain Modules/main.c:849 (python+0x48cd77) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #26 main Programs/python.c:15 (python+0x9abc7) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
    
    SUMMARY: ThreadSanitizer: data race Include/cpython/pyatomic_gcc.h:565 in _Py_atomic_store_ptr_release
    ==================
    Traceback (most recent call last):
      File "/cpython-main/example.py", line 42, in <module>
        main()
        ~~~~^^
      File "/cpython-main/example.py", line 38, in main
        f2.result()  # reraise
        ~~~~~~~~~^^
      File "/cpython-main/Lib/concurrent/futures/_base.py", line 443, in result
        return self.__get_result()
               ~~~~~~~~~~~~~~~~~^^
      File "/cpython-main/Lib/concurrent/futures/_base.py", line 395, in __get_result
        raise self._exception
      File "/cpython-main/Lib/concurrent/futures/thread.py", line 86, in run
        result = ctx.run(self.task)
      File "/cpython-main/Lib/concurrent/futures/thread.py", line 73, in run
        return fn(*args, **kwargs)
      File "/cpython-main/example.py", line 26, in test
        del obj.b
            ^^^^^
    AttributeError: b
    ThreadSanitizer: reported 1 warnings
    
    output-3.txt (not reproduced)
    WARNING: ThreadSanitizer: data race (pid=10250)
      Read of size 8 at 0x7f2d2a15b340 by thread T1:
        #0 PyMember_SetOne Python/structmember.c:177 (python+0x45baf8) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #1 member_set Objects/descrobject.c:239 (python+0x1afd6b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #2 _PyObject_GenericSetAttrWithDict Objects/object.c:2047 (python+0x230fc5) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #3 PyObject_GenericSetAttr Objects/object.c:2118 (python+0x2312e8) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #4 PyObject_SetAttr Objects/object.c:1531 (python+0x22ed96) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #5 PyObject_DelAttr Objects/object.c:1567 (python+0x22f08a) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #6 _PyEval_EvalFrameDefault Python/generated_cases.c.h:5377 (python+0x3832de) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #7 _PyEval_EvalFrame Include/internal/pycore_ceval.h:118 (python+0x399f70) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #8 _PyEval_Vector Python/ceval.c:2166 (python+0x39a1ee) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #9 _PyFunction_Vectorcall Objects/call.c:413 (python+0x1982c9) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #10 _PyObject_VectorcallTstate Include/internal/pycore_call.h:144 (python+0x1986f7) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #11 _PyObject_VectorcallPrepend Objects/call.c:855 (python+0x1996a8) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #12 method_vectorcall Objects/classobject.c:55 (python+0x19c88b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #13 _PyObject_VectorcallTstate Include/internal/pycore_call.h:144 (python+0x3c561b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #14 context_run Python/context.c:727 (python+0x3c65f1) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #15 method_vectorcall_FASTCALL_KEYWORDS Objects/descrobject.c:421 (python+0x1b071b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #16 _PyObject_VectorcallTstate Include/internal/pycore_call.h:144 (python+0x1986f7) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #17 PyObject_Vectorcall Objects/call.c:327 (python+0x19883d) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #18 _Py_VectorCallInstrumentation_StackRefSteal Python/ceval.c:775 (python+0x36f1ca) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #19 _PyEval_EvalFrameDefault Python/generated_cases.c.h:1841 (python+0x3790ab) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #20 _PyEval_EvalFrame Include/internal/pycore_ceval.h:118 (python+0x399f70) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #21 _PyEval_Vector Python/ceval.c:2166 (python+0x39a1ee) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #22 _PyFunction_Vectorcall Objects/call.c:413 (python+0x1982c9) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #23 _PyObject_VectorcallTstate Include/internal/pycore_call.h:144 (python+0x1986f7) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #24 _PyObject_VectorcallPrepend Objects/call.c:855 (python+0x1996a8) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #25 method_vectorcall Objects/classobject.c:55 (python+0x19c88b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #26 _PyVectorcall_Call Objects/call.c:273 (python+0x19a661) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #27 _PyObject_Call Objects/call.c:348 (python+0x19a9aa) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #28 PyObject_Call Objects/call.c:373 (python+0x19aa0a) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #29 thread_run Modules/_threadmodule.c:387 (python+0x537b2e) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #30 pythread_wrapper Python/thread_pthread.h:234 (python+0x47255f) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
    
      Previous atomic write of size 8 at 0x7f2d2a15b340 by thread T2:
        #0 _Py_atomic_store_ptr_release Include/cpython/pyatomic_gcc.h:565 (python+0x45c1b4) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #1 PyMember_SetOne Python/structmember.c:335 (python+0x45c1b4)
        #2 member_set Objects/descrobject.c:239 (python+0x1afd6b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #3 _PyObject_GenericSetAttrWithDict Objects/object.c:2047 (python+0x230fc5) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #4 PyObject_GenericSetAttr Objects/object.c:2118 (python+0x2312e8) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #5 PyObject_SetAttr Objects/object.c:1531 (python+0x22ed96) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #6 PyObject_DelAttr Objects/object.c:1567 (python+0x22f08a) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #7 _PyEval_EvalFrameDefault Python/generated_cases.c.h:5377 (python+0x3832de) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #8 _PyEval_EvalFrame Include/internal/pycore_ceval.h:118 (python+0x399f70) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #9 _PyEval_Vector Python/ceval.c:2166 (python+0x39a1ee) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #10 _PyFunction_Vectorcall Objects/call.c:413 (python+0x1982c9) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #11 _PyObject_VectorcallTstate Include/internal/pycore_call.h:144 (python+0x1986f7) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #12 _PyObject_VectorcallPrepend Objects/call.c:855 (python+0x1996a8) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #13 method_vectorcall Objects/classobject.c:55 (python+0x19c88b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #14 _PyObject_VectorcallTstate Include/internal/pycore_call.h:144 (python+0x3c561b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #15 context_run Python/context.c:727 (python+0x3c65f1) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #16 method_vectorcall_FASTCALL_KEYWORDS Objects/descrobject.c:421 (python+0x1b071b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #17 _PyObject_VectorcallTstate Include/internal/pycore_call.h:144 (python+0x1986f7) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #18 PyObject_Vectorcall Objects/call.c:327 (python+0x19883d) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #19 _Py_VectorCallInstrumentation_StackRefSteal Python/ceval.c:775 (python+0x36f1ca) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #20 _PyEval_EvalFrameDefault Python/generated_cases.c.h:1841 (python+0x3790ab) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #21 _PyEval_EvalFrame Include/internal/pycore_ceval.h:118 (python+0x399f70) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #22 _PyEval_Vector Python/ceval.c:2166 (python+0x39a1ee) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #23 _PyFunction_Vectorcall Objects/call.c:413 (python+0x1982c9) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #24 _PyObject_VectorcallTstate Include/internal/pycore_call.h:144 (python+0x1986f7) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #25 _PyObject_VectorcallPrepend Objects/call.c:855 (python+0x1996a8) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #26 method_vectorcall Objects/classobject.c:55 (python+0x19c88b) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #27 _PyVectorcall_Call Objects/call.c:273 (python+0x19a661) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #28 _PyObject_Call Objects/call.c:348 (python+0x19a9aa) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #29 PyObject_Call Objects/call.c:373 (python+0x19aa0a) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #30 thread_run Modules/_threadmodule.c:387 (python+0x537b2e) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #31 pythread_wrapper Python/thread_pthread.h:234 (python+0x47255f) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
    
      Thread T1 'ThreadPoolExecu' (tid=10252, running) created by main thread at:
        #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1022 (libtsan.so.2+0x568a6) (BuildId: 99ef88596cb10a8ccf307fe1a9070f66a44b1624)
        #1 do_start_joinable_thread Python/thread_pthread.h:281 (python+0x4729c9) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #2 PyThread_start_joinable_thread Python/thread_pthread.h:323 (python+0x472b6d) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #3 ThreadHandle_start Modules/_threadmodule.c:474 (python+0x5374fc) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #4 do_start_new_thread Modules/_threadmodule.c:1920 (python+0x5376fe) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #5 thread_PyThread_start_joinable_thread Modules/_threadmodule.c:2043 (python+0x537959) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #6 cfunction_call Objects/methodobject.c:564 (python+0x223185) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #7 _PyObject_MakeTpCall Objects/call.c:242 (python+0x198521) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #8 _PyObject_VectorcallTstate Include/internal/pycore_call.h:142 (python+0x19878a) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #9 PyObject_Vectorcall Objects/call.c:327 (python+0x19883d) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #10 _Py_VectorCallInstrumentation_StackRefSteal Python/ceval.c:775 (python+0x36f1ca) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #11 _PyEval_EvalFrameDefault Python/generated_cases.c.h:3222 (python+0x37d203) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #12 _PyEval_EvalFrame Include/internal/pycore_ceval.h:118 (python+0x399f70) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #13 _PyEval_Vector Python/ceval.c:2166 (python+0x39a1ee) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #14 PyEval_EvalCode Python/ceval.c:686 (python+0x39a336) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #15 run_eval_code_obj Python/pythonrun.c:1368 (python+0x44ea97) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #16 run_mod Python/pythonrun.c:1471 (python+0x44ed78) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #17 pyrun_file Python/pythonrun.c:1295 (python+0x44f7a1) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #18 _PyRun_SimpleFileObject Python/pythonrun.c:518 (python+0x4515fa) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #19 _PyRun_AnyFileObject Python/pythonrun.c:81 (python+0x4517fc) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #20 pymain_run_file_obj Modules/main.c:410 (python+0x48b858) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #21 pymain_run_file Modules/main.c:429 (python+0x48b9b4) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #22 pymain_run_python Modules/main.c:714 (python+0x48c8fa) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #23 Py_RunMain Modules/main.c:795 (python+0x48cbd2) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #24 pymain_main Modules/main.c:825 (python+0x48cc66) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #25 Py_BytesMain Modules/main.c:849 (python+0x48cd77) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #26 main Programs/python.c:15 (python+0x9abc7) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
    
      Thread T2 'ThreadPoolExecu' (tid=10253, running) created by main thread at:
        #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1022 (libtsan.so.2+0x568a6) (BuildId: 99ef88596cb10a8ccf307fe1a9070f66a44b1624)
        #1 do_start_joinable_thread Python/thread_pthread.h:281 (python+0x4729c9) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #2 PyThread_start_joinable_thread Python/thread_pthread.h:323 (python+0x472b6d) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #3 ThreadHandle_start Modules/_threadmodule.c:474 (python+0x5374fc) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #4 do_start_new_thread Modules/_threadmodule.c:1920 (python+0x5376fe) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #5 thread_PyThread_start_joinable_thread Modules/_threadmodule.c:2043 (python+0x537959) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #6 cfunction_call Objects/methodobject.c:564 (python+0x223185) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #7 _PyObject_MakeTpCall Objects/call.c:242 (python+0x198521) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #8 _PyObject_VectorcallTstate Include/internal/pycore_call.h:142 (python+0x19878a) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #9 PyObject_Vectorcall Objects/call.c:327 (python+0x19883d) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #10 _Py_VectorCall_StackRefSteal Python/ceval.c:733 (python+0x36f06f) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #11 _PyEval_EvalFrameDefault Python/generated_cases.c.h:3424 (python+0x37ddb3) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #12 _PyEval_EvalFrame Include/internal/pycore_ceval.h:118 (python+0x399f70) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #13 _PyEval_Vector Python/ceval.c:2166 (python+0x39a1ee) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #14 PyEval_EvalCode Python/ceval.c:686 (python+0x39a336) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #15 run_eval_code_obj Python/pythonrun.c:1368 (python+0x44ea97) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #16 run_mod Python/pythonrun.c:1471 (python+0x44ed78) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #17 pyrun_file Python/pythonrun.c:1295 (python+0x44f7a1) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #18 _PyRun_SimpleFileObject Python/pythonrun.c:518 (python+0x4515fa) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #19 _PyRun_AnyFileObject Python/pythonrun.c:81 (python+0x4517fc) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #20 pymain_run_file_obj Modules/main.c:410 (python+0x48b858) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #21 pymain_run_file Modules/main.c:429 (python+0x48b9b4) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #22 pymain_run_python Modules/main.c:714 (python+0x48c8fa) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #23 Py_RunMain Modules/main.c:795 (python+0x48cbd2) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #24 pymain_main Modules/main.c:825 (python+0x48cc66) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #25 Py_BytesMain Modules/main.c:849 (python+0x48cd77) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
        #26 main Programs/python.c:15 (python+0x9abc7) (BuildId: 2a85fcfbed9bca2cd9af7b0ac67e14b2ce712d4d)
    
    SUMMARY: ThreadSanitizer: data race Python/structmember.c:177 in PyMember_SetOne
    ==================
    ThreadSanitizer: reported 1 warnings
    

    I also tried running the test for 10 minutes:

    root@85d19837c2cd /cpython-main# time ./python example.py
    
    ________________________________________________________
    Executed in  606.04 secs    fish           external
       usr time   18.72 mins  626.00 micros   18.72 mins
       sys time    0.41 mins  738.00 micros    0.41 mins

    No errors, no warnings. All subsequent tries (11) after that were successful: 52.82±37.68 secs. In terms of the number of iterations required for reproduction, TSan increases them by about 20 times (~2K → ~40K).

  8. colesbury commented on Mar 23, 2026

    @colesbury
    Contributor

    Yeah, this looks like a bug to me. We should handle Py_T_OBJECT_EX in the delete code path the same way we handle it further on in PyMember_SetOne.

  9. diegorusso commented on Mar 25, 2026

    @diegorusso
    Contributor

    I guess this is something that @dpdani could take

  10. dpdani commented on Mar 25, 2026

    @dpdani
    Contributor

    Oops, it seems I forgot looking into that code path back then. It is definitely a bug, thank you for reporting that 👍

  11. x42005e1f commented on Mar 25, 2026

    @x42005e1f
    ContributorAuthor

    I should note that it would be possible to handle both __set__() and __delete__() without per-object locks, simply by using something like _Py_atomic_exchange_ptr() from pyatomic.h (and raising an AttributeError when both the new and old values are NULL). There is no wrapper for it in pycore_pyatomic_ft_wrappers.h, but as I saw in one PR, it can be used with #ifdef Py_GIL_DISABLED.


    Oh, wait, I saw the comments about this in the discussion of the first PR mentioned. Never mind.


    Hypothetically, it could be used reliably in PyMember_SetOne() if it were also used in PyMember_GetOne(): the getter would exchange the value with some special value, thereby preventing the setter from performing a decref. It would then attempt a compare-and-exchange back, and perform an incref only if successful. That way, only the getters would have to be synchronized. But this is a dubious benefit, and support for the special value would also have to be handled by C API users (or not? if they always use per-object locks or if some special value is safe, then the new behavior would not make any difference except for the possibility of concurrent writes while holding the lock, but I know too little about C API use cases). So yes, it seems that there is not much that can be done here.

    On the other hand, the technique I described optimizes my use case (slot.__delete__() as an atomic Python-level test-and-set). The optimistic path of PyMember_GetOne() is not going anywhere, so in the best-case scenario (read-only or write-only), all operations will be performed without per-object locks. But there is the problem with the special value...

  12. added 2 commits that reference this issue on May 6, 2026
  13. colesbury commented on May 6, 2026

    @colesbury
    Contributor

    Thanks for the bug report @x42005e1f and @dpdani for fixing this

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

Metadata

Metadata

Assignees

Labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions