You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
test_abc hangs on TSan Parallel Test on Free Threading #151593
Aha, using my PR adding timeouts, I managed to get traceback where test_abc hangs:
0:08:47 load avg: 0.02 mem: 486.4 MiB running (1): test_abc (8 min 47 sec)
0:09:17 load avg: 0.01 mem: 486.5 MiB running (1): test_abc (9 min 17 sec)
0:09:47 load avg: 0.01 mem: 486.5 MiB running (1): test_abc (9 min 47 sec)
0:10:03 load avg: 0.08 mem: 253.9 MiB [2/2/1] test_abc worker non-zero exit code (Exit code 1)
test_positional_only_and_kwonlyargs_with_init_subclass (test.test_abc.test_factory.<locals>.TestABCWithInitSubclass.test_positional_only_and_kwonlyargs_with_init_subclass) [threads=4] ... ok
test_works_with_init_subclass (test.test_abc.test_factory.<locals>.TestABCWithInitSubclass.test_works_with_init_subclass) [threads=4] ... ok
test_positional_only_and_kwonlyargs_with_init_subclass (test.test_abc.test_factory.<locals>.TestABCWithInitSubclass.test_positional_only_and_kwonlyargs_with_init_subclass) ... ok
test_works_with_init_subclass (test.test_abc.test_factory.<locals>.TestABCWithInitSubclass.test_works_with_init_subclass) ... ok
test_ABC_has___slots__ (test.test_abc.test_factory.<locals>.TestABC.test_ABC_has___slots__) [threads=4] ... ok
test_ABC_helper (test.test_abc.test_factory.<locals>.TestABC.test_ABC_helper) [threads=4] ... ok
test_abstractclassmethod_basics (test.test_abc.test_factory.<locals>.TestABC.test_abstractclassmethod_basics) [threads=4] ... ok
test_abstractmethod_basics (test.test_abc.test_factory.<locals>.TestABC.test_abstractmethod_basics) [threads=4] ... ok
test_abstractmethod_integration (test.test_abc.test_factory.<locals>.TestABC.test_abstractmethod_integration) [threads=4] ...
Timeout (0:10:00)!
Thread 0x00007fb4767ff6c0 [test_abstractme] (most recent call first):
File "/home/runner/work/cpython/cpython/Lib/abc.py", line 102 in __init__
File "/home/runner/work/cpython/cpython/Lib/test/test_abc.py", line 207 in C
File "/home/runner/work/cpython/cpython/Lib/test/test_abc.py", line 206 in test_abstractmethod_integration
File "/home/runner/work/cpython/cpython/Lib/contextlib.py", line 116 in inner
File "/home/runner/work/cpython/cpython/Lib/unittest/case.py", line 637 in _callTestMethod
File "/home/runner/work/cpython/cpython/Lib/unittest/case.py", line 691 in run
File "/home/runner/work/cpython/cpython/Lib/test/libregrtest/parallel_case.py", line 23 in run_worker
File "/home/runner/work/cpython/cpython/Lib/threading.py", line 1160 in run
File "/home/runner/work/cpython/cpython/Lib/threading.py", line 1218 in _bootstrap_inner
File "/home/runner/work/cpython/cpython/Lib/threading.py", line 1180 in _bootstrap
Thread 0x00007fb4789ff6c0 [test_abstractme] (most recent call first):
File "/home/runner/work/cpython/cpython/Lib/abc.py", line 102 in __init__
File "/home/runner/work/cpython/cpython/Lib/test/test_abc.py", line 207 in C
File "/home/runner/work/cpython/cpython/Lib/test/test_abc.py", line 206 in test_abstractmethod_integration
File "/home/runner/work/cpython/cpython/Lib/contextlib.py", line 116 in inner
File "/home/runner/work/cpython/cpython/Lib/unittest/case.py", line 637 in _callTestMethod
File "/home/runner/work/cpython/cpython/Lib/unittest/case.py", line 691 in run
File "/home/runner/work/cpython/cpython/Lib/test/libregrtest/parallel_case.py", line 23 in run_worker
File "/home/runner/work/cpython/cpython/Lib/threading.py", line 1160 in run
File "/home/runner/work/cpython/cpython/Lib/threading.py", line 1218 in _bootstrap_inner
File "/home/runner/work/cpython/cpython/Lib/threading.py", line 1180 in _bootstrap
Thread 0x00007fb47adff6c0 [test_abstractme] (most recent call first):
File "/home/runner/work/cpython/cpython/Lib/abc.py", line 128 in __new__
File "/home/runner/work/cpython/cpython/Lib/test/test_abc.py", line 223 in test_abstractmethod_integration
File "/home/runner/work/cpython/cpython/Lib/contextlib.py", line 116 in inner
File "/home/runner/work/cpython/cpython/Lib/unittest/case.py", line 637 in _callTestMethod
File "/home/runner/work/cpython/cpython/Lib/unittest/case.py", line 691 in run
File "/home/runner/work/cpython/cpython/Lib/test/libregrtest/parallel_case.py", line 23 in run_worker
File "/home/runner/work/cpython/cpython/Lib/threading.py", line 1160 in run
File "/home/runner/work/cpython/cpython/Lib/threading.py", line 1218 in _bootstrap_inner
File "/home/runner/work/cpython/cpython/Lib/threading.py", line 1180 in _bootstrap
Thread 0x00007fb479dfe6c0 [test_abstractme] (most recent call first):
File "/home/runner/work/cpython/cpython/Lib/traceback.py", line 316 in clear_frames
File "/home/runner/work/cpython/cpython/Lib/unittest/case.py", line 272 in __exit__
File "/home/runner/work/cpython/cpython/Lib/unittest/case.py", line 244 in handle
File "/home/runner/work/cpython/cpython/Lib/unittest/case.py", line 835 in assertRaises
File "/home/runner/work/cpython/cpython/Lib/test/test_abc.py", line 227 in test_abstractmethod_integration
File "/home/runner/work/cpython/cpython/Lib/contextlib.py", line 116 in inner
File "/home/runner/work/cpython/cpython/Lib/unittest/case.py", line 637 in _callTestMethod
File "/home/runner/work/cpython/cpython/Lib/unittest/case.py", line 691 in run
File "/home/runner/work/cpython/cpython/Lib/test/libregrtest/parallel_case.py", line 23 in run_worker
File "/home/runner/work/cpython/cpython/Lib/threading.py", line 1160 in run
File "/home/runner/work/cpython/cpython/Lib/threading.py", line 1218 in _bootstrap_inner
File "/home/runner/work/cpython/cpython/Lib/threading.py", line 1180 in _bootstrap
Thread 0x00007fb4d3b58f40 [python] (most recent call first):
File "/home/runner/work/cpython/cpython/Lib/threading.py", line 1269 in join
File "/home/runner/work/cpython/cpython/Lib/test/libregrtest/parallel_case.py", line 54 in run
File "/home/runner/work/cpython/cpython/Lib/unittest/case.py", line 747 in __call__
File "/home/runner/work/cpython/cpython/Lib/unittest/suite.py", line 122 in run
File "/home/runner/work/cpython/cpython/Lib/unittest/suite.py", line 84 in __call__
File "/home/runner/work/cpython/cpython/Lib/unittest/suite.py", line 122 in run
File "/home/runner/work/cpython/cpython/Lib/unittest/suite.py", line 84 in __call__
File "/home/runner/work/cpython/cpython/Lib/unittest/runner.py", line 256 in run
File "/home/runner/work/cpython/cpython/Lib/test/libregrtest/single.py", line 84 in _run_suite
File "/home/runner/work/cpython/cpython/Lib/test/libregrtest/single.py", line 42 in run_unittest
File "/home/runner/work/cpython/cpython/Lib/test/libregrtest/single.py", line 162 in test_func
File "/home/runner/work/cpython/cpython/Lib/test/libregrtest/single.py", line 118 in regrtest_runner
File "/home/runner/work/cpython/cpython/Lib/test/libregrtest/single.py", line 165 in _load_run_test
File "/home/runner/work/cpython/cpython/Lib/test/libregrtest/single.py", line 210 in _runtest_env_changed_exc
File "/home/runner/work/cpython/cpython/Lib/test/libregrtest/single.py", line 319 in _runtest
File "/home/runner/work/cpython/cpython/Lib/test/libregrtest/single.py", line 348 in run_single_test
File "/home/runner/work/cpython/cpython/Lib/test/libregrtest/worker.py", line 99 in worker_process
File "/home/runner/work/cpython/cpython/Lib/test/libregrtest/worker.py", line 137 in main
File "/home/runner/work/cpython/cpython/Lib/test/libregrtest/worker.py", line 141 in <module>
File "/home/runner/work/cpython/cpython/Lib/runpy.py", line 87 in _run_code
File "/home/runner/work/cpython/cpython/Lib/runpy.py", line 201 in _run_module_as_main
== Tests result: FAILURE ==
commit baae9cb159e240ee9474ce7c02f88c233390777a
Author: Neil Schemenauer <nas-github@arctrix.com>
Date: Tue Feb 25 21:24:20 2025 -0800
gh-117657: Use an atomic store to set type flags. (gh-127588)
The `PyType_HasFeature()` function reads the flags with a relaxed atomic
load and without holding the type lock. To avoid data races, use atomic
stores if `PyType_Ready()` has already been called.
commit fbbbc10055e0ee0011cf683132be706815480839
Author: Neil Schemenauer <nas-github@arctrix.com>
Date: Tue May 27 18:27:41 2025 -0700
gh-127266: avoid data races when updating type slots (gh-133177)
In the free-threaded build, avoid data races caused by updating type
slots or type flags after the type was initially created. For those
(typically rare) cases, use the stop-the-world mechanism. Remove the
use of atomics when reading or writing type flags.
TSan (--with-thread-sanitizer) is not needed to reproduce the issue. I can reproduce the issues on Python built with ./configure --with-pydebug --disable-gil.
type_set_abstractmethods() holds the type lock and waits for types_start_world(), whereas other threads are waiting for the type lock and are not suspended by the stop-the-world request. At the end, all threads are waiting for an event, but nothing happens since they are blocking each others.
I reproduced with ./configure --with-pydebug --disable-gil and ./python -m test test_abc --parallel-threads=10 on main (a173a6d).
I can't understand why _Py_LOCK_DONT_DETACH would be necessary for LOCK_KEYS, and there's no comment to explain it either. Furthermore, the test suite runs fine with this change, which would also fix the issue at hand:
Here is a reproducer, generated by Claude. Using the current main branch (55bc312), nogil build and without debug set, I get this output:
rounds=2000 writers=4 stoppers=4 -> stale reads = 3826
e.g. round 1 writer 3 stored ['value-1-3'] but read back the class attribute 'SENTINEL_1' (stale type version)
RACE REPRODUCED (this is a bug)
Another way I tried to fix this was doing a lock-free store of tp_version_tag = 0 under LOCK_KEYS. However, that races with assign_version_tag() and the store can get lost.
Activity
vstinner commentedon Jun 17, 2026
When the test doesn't hang, the whole command takes 14.1 seconds: https://github.com/python/cpython/actions/runs/27677669151/job/81856939320
vstinner commentedon Jun 17, 2026
Aha, using my PR adding timeouts, I managed to get traceback where test_abc hangs:
gh-151593: Use timeout on GitHub Action TSan jobs (#151594)
[3.14] gh-151593: Use timeout on GitHub Action TSan jobs (GH-151594) (#…
[3.15] gh-151593: Use timeout on GitHub Action TSan jobs (GH-151594) (#…
vstinner commentedon Jun 17, 2026
I'm able to reproduce the issue on my Fedora 44 laptop.
./configure --cache-file=../python-config.cache --with-pydebug --with-system-expat --with-thread-sanitizer --disable-gilFor example, test_ABC_helper() of test_abc hangs.
_PyEval_StopTheWorld()._PyThreadState_Attach().threads.join()(wait until tests complete)LOCK_KEYS(keys)callsPyMutex_LockFlags()with_Py_LOCK_DONT_DETACH.Summary of the 12 threads:
vstinner commentedon Jun 17, 2026
Full traceback of the 12 threads: traceback.txt.
vstinner commentedon Jun 17, 2026
Thread 40 calls
type_set_abstractmethods(), extract:First, it acquires the type lock. Then, it calls
_PyEval_StopTheWorld().BEGIN_TYPE_LOCK()was added by commit baae9cb.types_stop_world()was added by commit fbbbc10:vstinner commentedon Jun 17, 2026
TSan (
--with-thread-sanitizer) is not needed to reproduce the issue. I can reproduce the issues on Python built with./configure --with-pydebug --disable-gil.vstinner commentedon Jun 17, 2026
@nascheme @colesbury @kumaraditya303: It seems like this issue is a dead lock issue.
type_set_abstractmethods()holds the type lock and waits fortypes_start_world(), whereas other threads are waiting for the type lock and are not suspended by the stop-the-world request. At the end, all threads are waiting for an event, but nothing happens since they are blocking each others.dpdani commentedon Jun 17, 2026
I reproduced with
./configure --with-pydebug --disable-giland./python -m test test_abc --parallel-threads=10on main (a173a6d).I can't understand why
_Py_LOCK_DONT_DETACHwould be necessary forLOCK_KEYS, and there's no comment to explain it either. Furthermore, the test suite runs fine with this change, which would also fix the issue at hand:But this feels like a Chesterton fence situation.
dpdani commentedon Jun 17, 2026
Found it: #114741 (comment)
8 remaining items
StanFromIreland commentedon Jun 24, 2026
Will this be fixed soon? Otherwise can we please add a skip, it's quite painful to merge things, often having to re-run the job twice.
StanFromIreland commentedon Jun 25, 2026
I'm hitting this on almost every PR, I wrote #152173 to add a skip. It can be reverted when a proper fix is applied.
dpdani commentedon Jun 25, 2026
I'll take a look when I get the chance, but it might be a while.
pythongh-151593: Fix dead lock in PyDict insert_split_key()
vstinner commentedon Jun 25, 2026
I converted @nascheme's patch into a pull request: PR gh-152200.
gh-151593: Fix dead lock in PyDict insert_split_key() (#152200)
nascheme commentedon Jun 25, 2026
Hmm, I had made the same kind of PR and then closed it:
#152133 (comment)
I think moving
PyType_Modified()outside theLOCK_KEYSregion introduces a data race. I'd suggest we revert GH-150490.nascheme commentedon Jun 25, 2026
Here is a reproducer, generated by Claude. Using the current main branch (55bc312), nogil build and without debug set, I get this output:
Another way I tried to fix this was doing a lock-free store of
tp_version_tag = 0underLOCK_KEYS. However, that races withassign_version_tag()and the store can get lost.dict_split_key_race_demo.py.txt
vstinner commentedon Jun 25, 2026
nitpicking: it might be cleared to open a new issue for this data race.
colesbury commentedon Jun 25, 2026
I think that makes sense given that we've attempted to "fix forward" and introduced a different bug.
nascheme commentedon Jun 26, 2026
Closing, since the deadlock is fixed. I opened GH-152238 to track data-race issue.
gh-152238: Revert gh-150490 and gh-152200. (gh-152232)