diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py index 29babd7bf6996ad..2b89569a2857dc1 100644 --- a/Lib/test/test_sax.py +++ b/Lib/test/test_sax.py @@ -1039,6 +1039,26 @@ def test_expat_entityresolver_enabled(self): self.assertEqual(result.getvalue(), start + b"") + def test_expat_entityresolver_not_well_formed(self): + # gh-156796: the parser of an external entity was never finalized, + # so errors only detectable at the end of its input, such as an + # unclosed element, were silently ignored. + class NotWellFormedEntityResolver: + def resolveEntity(self, publicId, systemId): + inpsrc = InputSource() + inpsrc.setByteStream(BytesIO(b"")) + return inpsrc + + parser = create_parser() + parser.setFeature(feature_external_ges, True) + parser.setEntityResolver(NotWellFormedEntityResolver()) + parser.setContentHandler(XMLGenerator(BytesIO())) + + with self.assertRaises(SAXParseException): + parser.feed(']>' + '&test;') + parser.close() + def test_expat_entityresolver_default(self): parser = create_parser() self.assertEqual(parser.getFeature(feature_external_ges), False) diff --git a/Lib/xml/sax/expatreader.py b/Lib/xml/sax/expatreader.py index 37b1add28484877..1ce3b6b5e584fc3 100644 --- a/Lib/xml/sax/expatreader.py +++ b/Lib/xml/sax/expatreader.py @@ -238,9 +238,14 @@ def _close_source(self): file.close() def close(self): - if (self._entity_stack or self._parser is None or - isinstance(self._parser, _ClosedParser)): - # If we are completing an external entity, do nothing here + if self._parser is None or isinstance(self._parser, _ClosedParser): + return + if self._entity_stack: + # We are completing an external entity. Finalize its parser so + # that errors which are only detectable at the end of the input, + # such as an unclosed element, are reported, but do not end the + # document: the enclosing parse is still in progress. + self.feed(b"", isFinal=True) return try: self.feed(b"", isFinal=True) diff --git a/Misc/NEWS.d/next/Library/2026-09-02-00-00-00.gh-issue-156796.k7Qw2P.rst b/Misc/NEWS.d/next/Library/2026-09-02-00-00-00.gh-issue-156796.k7Qw2P.rst new file mode 100644 index 000000000000000..d5aadccaf3c37d9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-09-02-00-00-00.gh-issue-156796.k7Qw2P.rst @@ -0,0 +1,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.