Bug description:
_elementtree.c declares Py_MOD_GIL_NOT_USED but has several data races in the free-threaded build (audited for #116738):
PyDict_GetItemWithError in the expat entity handler returns a borrowed ref that another thread can invalidate by modifying the entity dict
concurrently
clear_extra / element_resize modify self->extra and the children array without any lock — concurrent append() + clear() on the same element
can crash
element_get_text, element_get_tail, element_get_attrib return borrowed refs into the struct with no lock held by the caller — a concurrent write
can free the pointed-to object before it's used
- All four property getters/setters (
tag, text, tail, attrib) access struct fields with no critical section
__copy__ snapshots struct fields without a lock
__deepcopy__ has the same problem and additionally calls PyDict_Next on attrib without a critical section on the dict
treebuilder_handle_end reads self->stack and decrements self->index without a lock
Fix and tests in #145569.
Bug description:
_elementtree.cdeclaresPy_MOD_GIL_NOT_USEDbut has several data races in the free-threaded build (audited for #116738):PyDict_GetItemWithErrorin the expat entity handler returns a borrowed ref that another thread can invalidate by modifying the entity dictconcurrently
clear_extra/element_resizemodifyself->extraand the children array without any lock — concurrentappend()+clear()on the same elementcan crash
element_get_text,element_get_tail,element_get_attribreturn borrowed refs into the struct with no lock held by the caller — a concurrent writecan free the pointed-to object before it's used
tag,text,tail,attrib) access struct fields with no critical section__copy__snapshots struct fields without a lock__deepcopy__has the same problem and additionally callsPyDict_Nextonattribwithout a critical section on the dicttreebuilder_handle_endreadsself->stackand decrementsself->indexwithout a lockFix and tests in #145569.