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'])
events = ("start", "end", "bogus")
with self.assertRaises(ValueError) as cm:
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"<?xml version='1.0' encoding='iso-8859-1'?>\n"
b"<body xmlns='http://&#233;ffbot.org/ns'\n"
@ -586,6 +596,21 @@ class ElementTreeTest(unittest.TestCase):
self.assertEqual(str(cm.exception),
'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):
elem = ET.Element("tag")
elem.text = "text"

View File

@ -1202,7 +1202,12 @@ def iterparse(source, events=None, parser=None):
if not hasattr(source, "read"):
source = open(source, "rb")
close_source = True
try:
return _IterParseIterator(source, events, parser, close_source)
except:
if close_source:
source.close()
raise
class XMLPullParser:
@ -1285,20 +1290,26 @@ class _IterParseIterator:
self.root = self._root = None
def __next__(self):
try:
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
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

View File

@ -95,6 +95,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.