Skip to content

Commit 02a9251

Browse files
committed
gh-158032: Keep the element tag alive during Element.iter comparison
1 parent 6893326 commit 02a9251

2 files changed

Lines changed: 32 additions & 1 deletion

File tree

‎Lib/test/test_xml_etree_c.py‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,35 @@ def test_xmlpullparser_leaks(self):
161161
del parser
162162
support.gc_collect()
163163

164+
def test_iter_tag_reentrant_compare(self):
165+
destroyed = []
166+
compared = []
167+
168+
class Tag:
169+
def __del__(self):
170+
destroyed.append(True)
171+
172+
def __eq__(self, other):
173+
child.tag = "replaced"
174+
return NotImplemented
175+
176+
__hash__ = object.__hash__
177+
178+
class Sought:
179+
def __eq__(self, other):
180+
if isinstance(other, Tag):
181+
compared.append(not destroyed)
182+
return NotImplemented
183+
184+
__hash__ = object.__hash__
185+
186+
root = cET.Element("root")
187+
child = cET.SubElement(root, "x")
188+
child.tag = Tag()
189+
self.assertEqual(list(root.iter(Sought())), [])
190+
self.assertEqual(compared, [True])
191+
self.assertEqual(child.tag, "replaced")
192+
164193
def test_dict_disappearing_during_get_item(self):
165194
# test fix for seg fault reported in issue 27946
166195
class X:

‎Modules/_elementtree.c‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2381,7 +2381,9 @@ elementiter_next(PyObject *op)
23812381
if (it->sought_tag == Py_None)
23822382
return (PyObject *)elem;
23832383

2384-
rc = PyObject_RichCompareBool(elem->tag, it->sought_tag, Py_EQ);
2384+
PyObject *tag = Py_NewRef(elem->tag);
2385+
rc = PyObject_RichCompareBool(tag, it->sought_tag, Py_EQ);
2386+
Py_DECREF(tag);
23852387
if (rc > 0)
23862388
return (PyObject *)elem;
23872389

0 commit comments

Comments
 (0)