From e3d4ec4766629c3cbcc1afb4e5c020894d5e2258 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 23 Nov 2015 15:44:03 +0200 Subject: Issue #25688: Fixed file leak in ElementTree.iterparse() raising an error. --- Lib/test/test_xml_etree.py | 29 +++++++++++++++++++++++++++-- Lib/xml/etree/ElementTree.py | 41 ++++++++++++++++++++++++++--------------- Misc/NEWS | 2 ++ 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index 8511cfe..5c2a2af 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -561,11 +561,21 @@ class ElementTreeTest(unittest.TestCase): self.assertEqual(res, ['start-ns', 'end-ns']) events = ("start", "end", "bogus") - with self.assertRaises(ValueError) as cm: - with open(SIMPLE_XMLFILE, "rb") as f: + with open(SIMPLE_XMLFILE, "rb") as f: + with self.assertRaises(ValueError) as cm: iterparse(f, events) + self.assertFalse(f.closed) self.assertEqual(str(cm.exception), "unknown event 'bogus'") + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings("always", category=ResourceWarning) + with self.assertRaises(ValueError) as cm: + iterparse(SIMPLE_XMLFILE, events) + self.assertEqual(str(cm.exception), "unknown event 'bogus'") + del cm + support.gc_collect() + self.assertEqual(w, []) + source = io.BytesIO( b"\n" b"junk") + it = iterparse(TESTFN) + action, elem = next(it) + self.assertEqual((action, elem.tag), ('end', 'document')) + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings("always", category=ResourceWarning) + with self.assertRaises(ET.ParseError) as cm: + next(it) + self.assertEqual(str(cm.exception), + 'junk after document element: line 1, column 12') + del cm, it + support.gc_collect() + self.assertEqual(w, []) + def test_writefile(self): elem = ET.Element("tag") elem.text = "text" diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py index 97eba8b..5a09b35 100644 --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -1206,7 +1206,12 @@ def iterparse(source, events=None, parser=None): if not hasattr(source, "read"): source = open(source, "rb") close_source = True - return _IterParseIterator(source, events, parser, close_source) + try: + return _IterParseIterator(source, events, parser, close_source) + except: + if close_source: + source.close() + raise class XMLPullParser: @@ -1289,20 +1294,26 @@ class _IterParseIterator: self.root = self._root = None def __next__(self): - while 1: - for event in self._parser.read_events(): - return event - if self._parser._parser is None: - self.root = self._root - if self._close_file: - self._file.close() - raise StopIteration - # load event buffer - data = self._file.read(16 * 1024) - if data: - self._parser.feed(data) - else: - self._root = self._parser._close_and_return_root() + try: + while 1: + for event in self._parser.read_events(): + return event + if self._parser._parser is None: + break + # load event buffer + data = self._file.read(16 * 1024) + if data: + self._parser.feed(data) + else: + self._root = self._parser._close_and_return_root() + self.root = self._root + except: + if self._close_file: + self._file.close() + raise + if self._close_file: + self._file.close() + raise StopIteration def __iter__(self): return self diff --git a/Misc/NEWS b/Misc/NEWS index dee8338..e336023 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -106,6 +106,8 @@ Core and Builtins Library ------- +- Issue #25688: Fixed file leak in ElementTree.iterparse() raising an error. + - Issue #23914: Fixed SystemError raised by unpickler on broken pickle data. - Issue #25691: Fixed crash on deleting ElementTree.Element attributes. -- cgit v0.12