Skip to content

gh-160525: Fix quadratic text concatenation in xml.dom.expatbuilder - #160526

Draft
gpshead wants to merge 2 commits into
python:mainfrom
gpshead:scanfix-expatbuilder-zrqnvcb1
Draft

gpshead wants to merge 2 commits into
python:mainfrom
gpshead:scanfix-expatbuilder-zrqnvcb1

Conversation

@gpshead

@gpshead gpshead commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

xml.dom.expatbuilder now collects the pieces of a run of character data in a list on the builder and joins them once, instead of copying the Text node's data on every Expat callback. The join happens at the top of every handler that adds a sibling or closes the element (start/end element in both ExpatBuilder and Namespaces, comment, PI, and the CDATA data handler), which is also before a DOMBuilderFilter or the whitespace stripping can look at the tree. The flush for CDATA is in the data handler and not in the start handler so that an empty section still does not end the run. The second commit keeps this correct for subclasses that replace those handlers without calling the base implementations: the fast path only appends while the pending Text node is still the last child of the current node, and any pending pieces are joined when parsing ends. New handlers should still call _flush_text() first, so that the Text node's data is complete whenever other code can look at it.

Parsing through xml.dom.xmlbuilder.DOMBuilder with a DOMBuilderFilter that rejects nodes is still quadratic. That comes mostly from Node.removeChild() scanning childNodes from the front, and is left for a separate issue.

Fixes #160525

ANT-2026-ZRQNVCB1 ANT-2026-QXYQ68DQ

…lder

Collect the pieces of a run of character data in a list and join them
once, instead of copying the Text node's data on every Expat callback.

ANT-2026-ZRQNVCB1 ANT-2026-QXYQ68DQ
…rridden

A subclass of ExpatBuilder can replace the element, comment or
processing instruction handlers without calling the base
implementations, which are what end the pending run of character data.
Check that the Text node being extended is still the last child of the
current node before adding to it, and join any pending pieces when
parsing ends, so that such subclasses keep building the same tree.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs backport to 3.11 only security fixes needs backport to 3.12 only security fixes needs backport to 3.13 only security fixes needs backport to 3.14 bugs and security fixes needs backport to 3.15 bugs and security fixes sprint type-security A security issue

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

xml.dom.minidom.parseString() takes quadratic time on text delivered in many pieces

1 participant