Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions Lib/plistlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)
Expand Down Expand Up @@ -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 <?xml ... ?> declaration
# naming an unknown encoding; neither is a ValueError, so it
# would otherwise escape uncaught instead of the documented
# InvalidFileException.
raise InvalidFileException()
Comment on lines +188 to +196

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This doesn't propagate the error messages so it won't be helpful. There are other places in plistlib that raises unexpected exceptions and we still don't know what to do with it. I would suggest we first discuss that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

For now:

  • remove the long comment, it doesn't indicate anything
  • appropriately create an exception message for that
  • test it

And also I would wait for the decision on the ci-fuzz issue first, though I think we should indeed raise InvalidFileException here as documented.

return self.root

def handle_entity_decl(self, entity_name, is_parameter_entity, value, base, system_id, public_id, notation_name):
Expand Down
18 changes: 18 additions & 0 deletions Lib/test/test_plistlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"<plist><dict>")
with self.assertRaises(plistlib.InvalidFileException):
plistlib.loads(b"<plist><foo></bar></plist>")
with self.assertRaises(plistlib.InvalidFileException):
plistlib.loads(b"<plist>&undefined_entity;</plist>")

def test_xml_plist_unknown_encoding(self):
# gh-155397: an <?xml ... ?> declaration naming an encoding unknown
# to Python must raise InvalidFileException, not the underlying
# LookupError.
with self.assertRaises(plistlib.InvalidFileException):
plistlib.loads(
b'<?xml version="1.0" encoding="BogusEncoding"?><plist></plist>')

def test_load_aware_datetime(self):
dt = plistlib.loads(b"<plist><date>2023-12-10T08:03:30Z</date></plist>",
aware_datetime=True)
Expand Down
Original file line number Diff line number Diff line change
@@ -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 ``<?xml ... ?>``
declaration naming an unknown encoding) when parsing a malformed XML plist.
Loading