@@ -66,10 +66,90 @@ PyList_Reverse:shared:
6666# is a list
6767PyList_SetSlice:shared:
6868
69- # Sort - per-object lock held; comparison callbacks may execute
70- # arbitrary Python code
69+ # Sort - per-object lock held; the list is emptied before sorting
70+ # so other threads may observe an empty list, but they won't see the
71+ # intermediate states of the sort
7172PyList_Sort:shared:
7273
7374# Extend - lock target list; also lock source when it is a
7475# list, set, or dict
7576PyList_Extend:shared:
77+
78+ # Creation - pure allocation, no shared state
79+ PyBytes_FromString:atomic:
80+ PyBytes_FromStringAndSize:atomic:
81+ PyBytes_DecodeEscape:atomic:
82+
83+ # Creation from formatting C primitives - pure allocation, no shared state
84+ PyBytes_FromFormat:atomic:
85+ PyBytes_FromFormatV:atomic:
86+
87+ # Creation from object - uses buffer protocol so may call arbitrary code;
88+ # safe as long as the buffer is not mutated by another thread during the operation
89+ PyBytes_FromObject:shared:
90+
91+ # Size - uses atomic load on free-threaded builds
92+ PyBytes_Size:atomic:
93+ PyBytes_GET_SIZE:atomic:
94+
95+ # Raw data - no locking; mutating it is unsafe if the bytes object is shared between threads
96+ PyBytes_AsString:compatible:
97+ PyBytes_AS_STRING:compatible:
98+ PyBytes_AsStringAndSize:compatible:
99+
100+ # Concatenation - uses buffer protocol; safe as long as buffer is not mutated by another thread during the operation
101+ PyBytes_Concat:shared:
102+ PyBytes_ConcatAndDel:shared:
103+ PyBytes_Join:shared:
104+
105+ # Resizing - safe if the object is unique
106+ _PyBytes_Resize:distinct:
107+
108+ # Repr - atomic as bytes are immutable
109+ PyBytes_Repr:atomic:
110+
111+ # Creation from object - may call arbitrary code
112+ PyByteArray_FromObject:shared:
113+
114+ # Creation - pure allocation, no shared state
115+ PyByteArray_FromStringAndSize:atomic:
116+
117+ # Concatenation - uses buffer protocol; safe as long as buffer is not mutated by another thread during the operation
118+ PyByteArray_Concat:shared:
119+
120+ # Size - uses atomic load on free-threaded builds
121+ PyByteArray_Size:atomic:
122+ PyByteArray_GET_SIZE:atomic:
123+
124+ # Raw data - no locking; mutating it is unsafe if the bytearray object is shared between threads
125+ PyByteArray_AsString:compatible:
126+ PyByteArray_AS_STRING:compatible:
127+
128+ # Capsule objects (Doc/c-api/capsule.rst)
129+
130+ # Type check - read ob_type pointer, always safe
131+ PyCapsule_CheckExact:atomic:
132+
133+ # Creation - pure allocation, no shared state
134+ PyCapsule_New:atomic:
135+
136+ # Validation - reads pointer and name fields; safe on distinct objects
137+ PyCapsule_IsValid:distinct:
138+
139+ # Getters - read struct fields; safe on distinct objects but
140+ # concurrent access to the same capsule requires external synchronization
141+ PyCapsule_GetPointer:distinct:
142+ PyCapsule_GetName:distinct:
143+ PyCapsule_GetDestructor:distinct:
144+ PyCapsule_GetContext:distinct:
145+
146+ # Setters - write struct fields; safe on distinct objects but
147+ # concurrent access to the same capsule requires external synchronization
148+ PyCapsule_SetPointer:distinct:
149+ PyCapsule_SetName:distinct:
150+ PyCapsule_SetDestructor:distinct:
151+ PyCapsule_SetContext:distinct:
152+
153+ # Import - looks up a capsule from a module attribute and
154+ # calls PyCapsule_GetPointer; may call arbitrary code
155+ PyCapsule_Import:compatible:
0 commit comments