diff --git a/Lib/plistlib.py b/Lib/plistlib.py index 93f3ef5e38af843..70c86f0b4575bf4 100644 --- a/Lib/plistlib.py +++ b/Lib/plistlib.py @@ -67,7 +67,7 @@ import os import re import struct -from xml.parsers.expat import ParserCreate +from xml.parsers.expat import ExpatError, ParserCreate PlistFormat = enum.Enum('PlistFormat', 'FMT_XML FMT_BINARY', module=__name__) @@ -185,7 +185,15 @@ def parse(self, fileobj): self.parser.EndElementHandler = self.handle_end_element self.parser.CharacterDataHandler = self.handle_data self.parser.EntityDeclHandler = self.handle_entity_decl - self.parser.ParseFile(fileobj) + try: + self.parser.ParseFile(fileobj) + except (ExpatError, LookupError): + # gh-155397: ExpatError is raised for XML that is not + # well-formed, and LookupError for a declaration + # naming an unknown encoding; neither is a ValueError, so it + # would otherwise escape uncaught instead of the documented + # InvalidFileException. + raise InvalidFileException() return self.root def handle_entity_decl(self, entity_name, is_parameter_entity, value, base, system_id, public_id, notation_name): diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py index b9c261310bb5670..e6f19bbdf97212a 100644 --- a/Lib/test/test_plistlib.py +++ b/Lib/test/test_plistlib.py @@ -933,6 +933,24 @@ def test_xml_plist_with_entity_decl(self): "XML entity declarations are not supported"): plistlib.loads(XML_PLIST_WITH_ENTITY, fmt=plistlib.FMT_XML) + def test_xml_plist_not_well_formed(self): + # gh-155397: malformed XML must raise InvalidFileException, not the + # underlying xml.parsers.expat.ExpatError. + with self.assertRaises(plistlib.InvalidFileException): + plistlib.loads(b"") + with self.assertRaises(plistlib.InvalidFileException): + plistlib.loads(b"") + with self.assertRaises(plistlib.InvalidFileException): + plistlib.loads(b"&undefined_entity;") + + def test_xml_plist_unknown_encoding(self): + # gh-155397: an declaration naming an encoding unknown + # to Python must raise InvalidFileException, not the underlying + # LookupError. + with self.assertRaises(plistlib.InvalidFileException): + plistlib.loads( + b'') + def test_load_aware_datetime(self): dt = plistlib.loads(b"2023-12-10T08:03:30Z", aware_datetime=True) diff --git a/Misc/NEWS.d/next/Library/2026-08-08-17-00-00.gh-issue-155397.pL3xq9.rst b/Misc/NEWS.d/next/Library/2026-08-08-17-00-00.gh-issue-155397.pL3xq9.rst new file mode 100644 index 000000000000000..e5591a9527e3fb0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-08-17-00-00.gh-issue-155397.pL3xq9.rst @@ -0,0 +1,4 @@ +Fix :mod:`plistlib` to raise :exc:`~plistlib.InvalidFileException` instead +of leaking the underlying :exc:`xml.parsers.expat.ExpatError` (for +not-well-formed XML) or :exc:`LookupError` (for an ```` +declaration naming an unknown encoding) when parsing a malformed XML plist.