There are a few thread-safety issues with intern_common:
It can return a string that's not marked as interned because we insert into interned before we mark the string as interned. This can be fixed with some additional locking.
The Py_SET_REFCNT(s, Py_REFCNT(s) - 2) modification is not thread-safe with respect to other reference count modifications in the free threading build
Thanks. Is this is with 3.13? I think that one was fixed in #128196, but it's not backported to 3.13. That particular PR changes the data types of public fields, so I don't think we can backport it.
It might be worth doing the thread sanitizer tests on 3.14. cc @ngoldbaum
I want to re-do the TSAN PyO3 tests with 3.14, but I need to update the FFI definitions first. Generally PyO3 doesn't add support for new python versions until beta 1 to avoid dealing with churn.
Activity
lysnikolaou commented on Feb 13, 2025
I hit this while testing PyYAML (though the TSAN stack trace was slightly different). Are you going to work on this @colesbury?
colesbury commented on Feb 13, 2025
Yes, I'll probably put up a PR today.
Would you please share the TSAN stack trace?
pythongh-129701: Fix a data race in `intern_common` in the free threa…
lysnikolaou commented on Feb 13, 2025
Sure, here it is.
Read of size 4 at 0x0001202900c0 by thread T913: #0 unicode_eq eq.h:13 (python3.13:arm64+0x10017fec0) #1 unicodekeys_lookup_unicode dictobject.c:1151 (python3.13:arm64+0x100168360) #2 _Py_dict_lookup dictobject.c:1262 (python3.13:arm64+0x1001687d4) #3 dict_setdefault_ref_lock_held dictobject.c:4282 (python3.13:arm64+0x100174e0c) #4 PyDict_SetDefaultRef dictobject.c:4332 (python3.13:arm64+0x100174874) #5 intern_common unicodeobject.c:15277 (python3.13:arm64+0x10026b444) #6 _PyUnicode_InternMortal unicodeobject.c:15338 (python3.13:arm64+0x10026b9f8) #7 _PyCode_New codeobject.c:688 (python3.13:arm64+0x1000ef704) #8 PyCode_NewEmpty codeobject.c:936 (python3.13:arm64+0x1000f0c9c) ... Previous write of size 4 at 0x0001202900c0 by thread T915: #0 intern_common unicodeobject.c:15312 (python3.13:arm64+0x10026b784) #1 _PyUnicode_InternMortal unicodeobject.c:15338 (python3.13:arm64+0x10026b9f8) #2 _PyCode_New codeobject.c:688 (python3.13:arm64+0x1000ef704) #3 PyCode_NewEmpty codeobject.c:936 (python3.13:arm64+0x1000f0c9c) ...colesbury commented on Feb 13, 2025
Thanks. Is this is with 3.13? I think that one was fixed in #128196, but it's not backported to 3.13. That particular PR changes the data types of public fields, so I don't think we can backport it.
It might be worth doing the thread sanitizer tests on 3.14. cc @ngoldbaum
ngoldbaum commented on Feb 13, 2025
I think I've seen similar tracebacks on 3.13 with PyO3 about interning strings. See this line in the gist from this PyO3 issue.
I want to re-do the TSAN PyO3 tests with 3.14, but I need to update the FFI definitions first. Generally PyO3 doesn't add support for new python versions until beta 1 to avoid dealing with churn.
pythongh-129701: Fix a data race in `intern_common` in the free threa…
lysnikolaou commented on Feb 13, 2025
Yes, it's with 3.13.2. I'll try 3.14 later today or early tomorrow.
lysnikolaou commented on Feb 14, 2025
FWIW I did verify that the unicode_eq stack trace does not appear under 3.14.
gh-129701: Fix a data race in `intern_common` in the free threaded bu…
colesbury commented on Feb 25, 2025
I'm going to close this as the only remaining issue is that _Py_SetImmortal is not thread-safe in some circumstances, which is tracked in: