Skip to content

Commit e5c3261

Browse files
committed
gh-148731: Fix Element.iter() crash on OOM
Initialize ElementIterObject fields before allocating parent_stack so the partially initialized iterator can be safely deallocated if PyMem_New() fails. Add a regression test covering the MemoryError path in Element.iter().
1 parent d206d42 commit e5c3261

File tree

3 files changed

+32
-1
lines changed

3 files changed

+32
-1
lines changed

Lib/test/test_xml_etree_c.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import io
33
import struct
44
from test import support
5-
from test.support.import_helper import import_fresh_module
5+
from test.support.import_helper import import_fresh_module, import_module
66
import types
77
import unittest
88

@@ -15,6 +15,10 @@
1515

1616
@unittest.skipUnless(cET, 'requires _elementtree')
1717
class MiscTests(unittest.TestCase):
18+
@classmethod
19+
def setUpClass(cls):
20+
cls.testcapi = import_module('_testcapi')
21+
1822
# Issue #8651.
1923
@support.bigmemtest(size=support._2G + 100, memuse=1, dry_run=False)
2024
def test_length_overflow(self, size):
@@ -183,6 +187,23 @@ def __hash__(self):
183187
r = e.get(X())
184188
self.assertIsNone(r)
185189

190+
@unittest.skipIf(support.Py_TRACE_REFS,
191+
'Py_TRACE_REFS conflicts with testcapi.set_nomemory')
192+
def test_iter_oom_no_crash(self):
193+
# gh-148731: OOM while creating an Element iterator should raise
194+
# MemoryError without crashing while deallocating a partially
195+
# initialized iterator object.
196+
element = cET.Element('root')
197+
raised = False
198+
self.testcapi.set_nomemory(1, 2)
199+
try:
200+
element.iter()
201+
except MemoryError:
202+
raised = True
203+
finally:
204+
self.testcapi.remove_mem_hooks()
205+
self.assertTrue(raised, "MemoryError not raised")
206+
186207
@support.cpython_only
187208
def test_immutable_types(self):
188209
root = cET.fromstring('<a></a>')
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a crash in :mod:`xml.etree.ElementTree` when
2+
:meth:`~xml.etree.ElementTree.Element.iter` fails with :exc:`MemoryError`
3+
while creating the C accelerator iterator.

Modules/_elementtree.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2359,6 +2359,13 @@ create_elementiter(elementtreestate *st, ElementObject *self, PyObject *tag,
23592359
if (!it)
23602360
return NULL;
23612361

2362+
it->parent_stack = NULL;
2363+
it->parent_stack_used = 0;
2364+
it->parent_stack_size = 0;
2365+
it->root_element = NULL;
2366+
it->sought_tag = NULL;
2367+
it->gettext = 0;
2368+
23622369
it->sought_tag = Py_NewRef(tag);
23632370
it->gettext = gettext;
23642371
it->root_element = (ElementObject*)Py_NewRef(self);

0 commit comments

Comments
 (0)