thread A and B are simultaneously interning strings
thread A succeeds at inserting that string into the intern dictionary, and is at the end of intern_common immortalizing the string, which sets the .interned field on the string
thread B is now trying to intern a string and is performing an equality test during the intern dictionary lookup, which reads the .kind field.
The .kind and .interned fields are bitfields in the same word, so this is a race, and I can't see any synchronization or atomicity that would prevent it.
Perhaps we need to hold the critical section on the intern dictionary longer, until immortalization is complete?
We want to be able to read interned without holding a lock. Atomics don't mix well with bitfields, so I think the easiest thing would be to move interned out of the bitfield into its own byte and shrink the padding bits. The total size shouldn't need to change.
In summary:
The interned field, which can change if/when the string object is interned, gets its own byte so that it can be read atomically without a lock
The remaining bitfields (kind, compact, ascii, statically_allocated) are effectively immutable
@hawkinspae23a01 is now merged, so it should be okay at 3.14, but we are not going to backport this patch into 3.13 since it will raise compatibility issue who use Python 3.13 with GIL and free-threaded build.
Activity
colesbury commented on Dec 21, 2024
We want to be able to read interned without holding a lock. Atomics don't mix well with bitfields, so I think the easiest thing would be to move interned out of the bitfield into its own byte and shrink the padding bits. The total size shouldn't need to change.
In summary:
pythongh-128137: Split out interned field from state
gh-128137: Update PyASCIIObject to handle interned field with the ato…
corona10 commented on Jan 5, 2025
@hawkinsp ae23a01 is now merged, so it should be okay at 3.14, but we are not going to backport this patch into 3.13 since it will raise compatibility issue who use Python 3.13 with GIL and free-threaded build.
See: #128196 (comment)
pythongh-128137: Update PyASCIIObject to handle interned field with t…
pythongh-128137: Update PyASCIIObject to handle interned field with t…