Issue #25688: Fixed file leak in ElementTree.iterparse() raising an error.

This commit is contained in:
Serhiy Storchaka 2015-11-23 15:46:14 +02:00
commit 698068b013
3 changed files with 55 additions and 17 deletions

View file

@ -561,11 +561,21 @@ class ElementTreeTest(unittest.TestCase):
self.assertEqual(res, ['start-ns', 'end-ns']) self.assertEqual(res, ['start-ns', 'end-ns'])
events = ("start", "end", "bogus") 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) iterparse(f, events)
self.assertFalse(f.closed)
self.assertEqual(str(cm.exception), "unknown event 'bogus'") 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( source = io.BytesIO(
b"<?xml version='1.0' encoding='iso-8859-1'?>\n" b"<?xml version='1.0' encoding='iso-8859-1'?>\n"
b"<body xmlns='http://&#233;ffbot.org/ns'\n" b"<body xmlns='http://&#233;ffbot.org/ns'\n"
@ -586,6 +596,21 @@ class ElementTreeTest(unittest.TestCase):
self.assertEqual(str(cm.exception), self.assertEqual(str(cm.exception),
'junk after document element: line 1, column 12') 'junk after document element: line 1, column 12')
with open(TESTFN, "wb") as f:
f.write(b"<document />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): def test_writefile(self):
elem = ET.Element("tag") elem = ET.Element("tag")
elem.text = "text" elem.text = "text"

View file

@ -1202,7 +1202,12 @@ def iterparse(source, events=None, parser=None):
if not hasattr(source, "read"): if not hasattr(source, "read"):
source = open(source, "rb") source = open(source, "rb")
close_source = True 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: class XMLPullParser:
@ -1285,20 +1290,26 @@ class _IterParseIterator:
self.root = self._root = None self.root = self._root = None
def __next__(self): def __next__(self):
while 1: try:
for event in self._parser.read_events(): while 1:
return event for event in self._parser.read_events():
if self._parser._parser is None: return event
self.root = self._root if self._parser._parser is None:
if self._close_file: break
self._file.close() # load event buffer
raise StopIteration data = self._file.read(16 * 1024)
# load event buffer if data:
data = self._file.read(16 * 1024) self._parser.feed(data)
if data: else:
self._parser.feed(data) self._root = self._parser._close_and_return_root()
else: self.root = self._root
self._root = self._parser._close_and_return_root() except:
if self._close_file:
self._file.close()
raise
if self._close_file:
self._file.close()
raise StopIteration
def __iter__(self): def __iter__(self):
return self return self

View file

@ -95,6 +95,8 @@ Core and Builtins
Library Library
------- -------
- Issue #25688: Fixed file leak in ElementTree.iterparse() raising an error.
- Issue #23914: Fixed SystemError raised by unpickler on broken pickle data. - Issue #23914: Fixed SystemError raised by unpickler on broken pickle data.
- Issue #25691: Fixed crash on deleting ElementTree.Element attributes. - Issue #25691: Fixed crash on deleting ElementTree.Element attributes.