Skip to content

gh-156796: Finalize the parser of an external entity in xml.sax - #156828

Open
skdas20 wants to merge 1 commit into
python:mainfrom
skdas20:gh-156796-finalize-external-entity-parser
Open

gh-156796: Finalize the parser of an external entity in xml.sax#156828
skdas20 wants to merge 1 commit into
python:mainfrom
skdas20:gh-156796-finalize-external-entity-parser

Conversation

@skdas20

@skdas20 skdas20 commented Sep 2, 2026

Copy link
Copy Markdown

ExpatParser.close() returned early whenever _entity_stack was non-empty:

if (self._entity_stack or self._parser is None or
    isinstance(self._parser, _ClosedParser)):
    # If we are completing an external entity, do nothing here
    return

external_entity_ref() swaps in a parser from ExternalEntityParserCreate() and then calls IncrementalParser.parse(), which ends with self.close(). Because the stack is non-empty at that point, feed(b"", isFinal=True) was never reached, so expat never checked the entity's input for completeness and content that is not well-formed was accepted silently.

The guard is still needed — ending the document while an entity is being parsed would be wrong — so this finalizes the entity's parser and returns without calling endDocument(). The None/_ClosedParser checks are hoisted above it so they still apply on that path.

Verification

The reproducer from the issue silently succeeds on main. With this change it fails as you described:

xml.sax._exceptions.SAXParseException: <unknown>:1:8: error in processing external entity reference

test_expat_entityresolver_not_well_formed in Lib/test/test_sax.py covers it, and fails on unpatched main. The full test_sax passes (188 tests), which matches your note that finalizing the entity parser leaves the existing suite green.

I confirmed the behaviour is longstanding — the reproducer is silently accepted on 3.12 as well.

Fixes #156796

ExpatParser.close() returned early whenever _entity_stack was not empty,
so feed(b"", isFinal=True) was never called for the parser created by
external_entity_ref(). Expat therefore never checked the entity's input
for completeness, and an external entity whose content is not well-formed
was silently accepted. Errors expat detects while feeding data, such as a
mismatched tag, were still reported; only those detectable at the end of
the input, such as an unclosed element, were lost.

Finalize the entity's parser in that case, while still leaving the
document open, since the enclosing parse is what the early return was
there to protect.
Comment on lines +1 to +4
Fix :mod:`xml.sax` not reporting an external entity whose content is not
well-formed. The parser created for the entity was never finalized, so errors
which are only detectable at the end of its input, such as an unclosed
element, were silently ignored.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the second sentence could be ommited, since it's an implementation detail?

Suggested change
Fix :mod:`xml.sax` not reporting an external entity whose content is not
well-formed. The parser created for the entity was never finalized, so errors
which are only detectable at the end of its input, such as an unclosed
element, were silently ignored.
Fix :mod:`xml.sax` silently accepting an external entity whose content is not
well-formed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

xml.sax: the content of an external entity is not checked to be well-formed

2 participants