Uh oh!
There was an error while loading. Please reload this page.
gh-149816: Fix race conditions in Modules/_elementtree.c with free-threaded - #149918
gh-149816: Fix race conditions in Modules/_elementtree.c with free-threaded#149918ByteFlowing1337 wants to merge 9 commits into
Modules/_elementtree.c with free-threaded#149918Conversation
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
ByteFlowing1337
commented
Jun 10, 2026
@dpdani Thanks for you review! |
devdanzin
commented
Jul 19, 2026
Independent confirmation of item (69) "Unsynchronized extra pointer dereference in len in Minimal deterministic reproducer (exit 66 under TSan; importthreadingimportxml.etree.ElementTreeasETNTHREADS=8barrier=threading.Barrier(NTHREADS)
defworker(elem):
barrier.wait()
for_inrange(4000):
_=elem.attrib# if (!self->extra) create_extra(...) -- unlocked lazy init_=len(elem) # element_length reads self->extrafor_inrange(200):
shared=ET.Element("tag") # extra == NULL until first attrib/child touchts= [threading.Thread(target=worker, args=(shared,)) for_inrange(NTHREADS)]
fortints: t.start()
fortints: t.join()Confirmed still present on current (Found by |
dpdani
left a comment
There was a problem hiding this comment.
Unfortunately, this approach is not going to be effective. While it does resolve the sharpest edges, it still leaves some race conditions that need to be resolved.
| return -1; | ||
| } | ||
| Py_BEGIN_CRITICAL_SECTION(self); |
There was a problem hiding this comment.
Don't do locking here. There are a few callers of this function, and locking should be moved to the callers. For instance, this code in element_resize would not be thread safe with an inner critical section:
if (!self->extra) {
if (create_extra(self, NULL) <0)
return-1;
}Allocations and init functions need not be thread safe.
| if (!self->extra) | ||
| return; | ||
| Py_BEGIN_CRITICAL_SECTION(self); |
There was a problem hiding this comment.
Do not add locking here. The only code path that may call this code concurrently is in element_setstate_from_attributes, and locking should be moved there. It is probably needed anyway by the looks of it.
| Py_VISIT(JOIN_OBJ(self->text)); | ||
| Py_VISIT(JOIN_OBJ(self->tail)); | ||
| Py_BEGIN_CRITICAL_SECTION(self); |
There was a problem hiding this comment.
The GC runs during a stop-the-world pause, so there's no need for locking here.
This PR fixes
(69) Unsynchronized extra pointer dereference in len in Modules/_elementtree.cmentioned in #149816.It also fixes race condition in getting
attrib.