Skip to content

Commit 9c2c42c

Browse files
bpo-27863: Fixed multiple crashes in ElementTree. (#765) (#903) (#963)
(cherry picked from commit 576def0) (cherry picked from commit a6b4e19)
1 parent 68903b6 commit 9c2c42c

File tree

3 files changed

+131
-41
lines changed

3 files changed

+131
-41
lines changed

Lib/test/test_xml_etree.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,6 +1594,83 @@ def test_recursive_repr(self):
15941594
with self.assertRaises(RuntimeError):
15951595
repr(e) # Should not crash
15961596

1597+
def test_element_get_text(self):
1598+
# Issue #27863
1599+
class X(str):
1600+
def __del__(self):
1601+
try:
1602+
elem.text
1603+
except NameError:
1604+
pass
1605+
1606+
b = ET.TreeBuilder()
1607+
b.start('tag', {})
1608+
b.data('ABCD')
1609+
b.data(X('EFGH'))
1610+
b.data('IJKL')
1611+
b.end('tag')
1612+
1613+
elem = b.close()
1614+
self.assertEqual(elem.text, 'ABCDEFGHIJKL')
1615+
1616+
def test_element_get_tail(self):
1617+
# Issue #27863
1618+
class X(str):
1619+
def __del__(self):
1620+
try:
1621+
elem[0].tail
1622+
except NameError:
1623+
pass
1624+
1625+
b = ET.TreeBuilder()
1626+
b.start('root', {})
1627+
b.start('tag', {})
1628+
b.end('tag')
1629+
b.data('ABCD')
1630+
b.data(X('EFGH'))
1631+
b.data('IJKL')
1632+
b.end('root')
1633+
1634+
elem = b.close()
1635+
self.assertEqual(elem[0].tail, 'ABCDEFGHIJKL')
1636+
1637+
def test_element_iter(self):
1638+
# Issue #27863
1639+
e = ET.Element('tag')
1640+
e.extend([None]) # non-Element
1641+
1642+
it = e.iter()
1643+
self.assertIs(next(it), e)
1644+
self.assertRaises((AttributeError, TypeError), list, it)
1645+
1646+
def test_subscr(self):
1647+
# Issue #27863
1648+
class X:
1649+
def __index__(self):
1650+
del e[:]
1651+
return 1
1652+
1653+
e = ET.Element('elem')
1654+
e.append(ET.Element('child'))
1655+
e[:X()] # shouldn't crash
1656+
1657+
e.append(ET.Element('child'))
1658+
e[0:10:X()] # shouldn't crash
1659+
1660+
def test_ass_subscr(self):
1661+
# Issue #27863
1662+
class X:
1663+
def __index__(self):
1664+
e[:] = []
1665+
return 1
1666+
1667+
e = ET.Element('elem')
1668+
for _ in range(10):
1669+
e.insert(0, ET.Element('child'))
1670+
1671+
e[0:10:X()] = [] # shouldn't crash
1672+
1673+
15971674
class MutatingElementPath(str):
15981675
def __new__(cls, elem, *args):
15991676
self = str.__new__(cls, *args)

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ Extension Modules
4242
Library
4343
-------
4444

45+
- bpo-27863: Fixed multiple crashes in ElementTree caused by race conditions
46+
and wrong types.
47+
4548
- bpo-29942: Fix a crash in itertools.chain.from_iterable when encountering
4649
long runs of empty iterables.
4750

Modules/_elementtree.c

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -164,21 +164,18 @@ deepcopy(PyObject* object, PyObject* memo)
164164
LOCAL(PyObject*)
165165
list_join(PyObject* list)
166166
{
167-
/* join list elements (destroying the list in the process) */
168-
167+
/* join list elements */
169168
PyObject* joiner;
170169
PyObject* function;
171170
PyObject* args;
172171
PyObject* result;
173172

174173
switch (PyList_GET_SIZE(list)) {
175174
case 0:
176-
Py_DECREF(list);
177175
return PyString_FromString("");
178176
case 1:
179177
result = PyList_GET_ITEM(list, 0);
180178
Py_INCREF(result);
181-
Py_DECREF(list);
182179
return result;
183180
}
184181

@@ -196,9 +193,13 @@ list_join(PyObject* list)
196193
}
197194

198195
args = PyTuple_New(1);
199-
if (!args)
196+
if (!args) {
197+
Py_DECREF(function);
198+
Py_DECREF(joiner);
200199
return NULL;
200+
}
201201

202+
Py_INCREF(list);
202203
PyTuple_SET_ITEM(args, 0, list);
203204

204205
result = PyObject_CallObject(function, args);
@@ -435,15 +436,17 @@ element_get_text(ElementObject* self)
435436
{
436437
/* return borrowed reference to text attribute */
437438

438-
PyObject* res = self->text;
439+
PyObject *res = self->text;
439440

440441
if (JOIN_GET(res)) {
441442
res = JOIN_OBJ(res);
442443
if (PyList_CheckExact(res)) {
443-
res = list_join(res);
444-
if (!res)
444+
PyObject *tmp = list_join(res);
445+
if (!tmp)
445446
return NULL;
446-
self->text = res;
447+
self->text = tmp;
448+
Py_DECREF(res);
449+
res = tmp;
447450
}
448451
}
449452

@@ -455,15 +458,17 @@ element_get_tail(ElementObject* self)
455458
{
456459
/* return borrowed reference to text attribute */
457460

458-
PyObject* res = self->tail;
461+
PyObject *res = self->tail;
459462

460463
if (JOIN_GET(res)) {
461464
res = JOIN_OBJ(res);
462465
if (PyList_CheckExact(res)) {
463-
res = list_join(res);
464-
if (!res)
466+
PyObject *tmp = list_join(res);
467+
if (!tmp)
465468
return NULL;
466-
self->tail = res;
469+
self->tail = tmp;
470+
Py_DECREF(res);
471+
res = tmp;
467472
}
468473
}
469474

@@ -1730,6 +1735,37 @@ treebuilder_dealloc(TreeBuilderObject* self)
17301735
PyObject_Del(self);
17311736
}
17321737

1738+
/* -------------------------------------------------------------------- */
1739+
/* helpers for handling of arbitrary element-like objects */
1740+
1741+
static void
1742+
treebuilder_set_element_text_or_tail(PyObject **data, PyObject **dest)
1743+
{
1744+
PyObject *tmp = JOIN_OBJ(*dest);
1745+
*dest = JOIN_SET(*data, PyList_CheckExact(*data));
1746+
*data = NULL;
1747+
Py_DECREF(tmp);
1748+
}
1749+
1750+
LOCAL(void)
1751+
treebuilder_flush_data(TreeBuilderObject* self)
1752+
{
1753+
ElementObject *element = self->last;
1754+
1755+
if (self->data) {
1756+
if (self->this == element) {
1757+
treebuilder_set_element_text_or_tail(
1758+
&self->data,
1759+
&element->text);
1760+
}
1761+
else {
1762+
treebuilder_set_element_text_or_tail(
1763+
&self->data,
1764+
&element->tail);
1765+
}
1766+
}
1767+
}
1768+
17331769
LOCAL(int)
17341770
treebuilder_append_event(TreeBuilderObject *self, PyObject *action,
17351771
PyObject *node)
@@ -1764,20 +1800,7 @@ treebuilder_handle_start(TreeBuilderObject* self, PyObject* tag,
17641800
PyObject* node;
17651801
PyObject* this;
17661802

1767-
if (self->data) {
1768-
if (self->this == self->last) {
1769-
Py_DECREF(JOIN_OBJ(self->last->text));
1770-
self->last->text = JOIN_SET(
1771-
self->data, PyList_CheckExact(self->data)
1772-
);
1773-
} else {
1774-
Py_DECREF(JOIN_OBJ(self->last->tail));
1775-
self->last->tail = JOIN_SET(
1776-
self->data, PyList_CheckExact(self->data)
1777-
);
1778-
}
1779-
self->data = NULL;
1780-
}
1803+
treebuilder_flush_data(self);
17811804

17821805
node = element_new(tag, attrib);
17831806
if (!node)
@@ -1867,20 +1890,7 @@ treebuilder_handle_end(TreeBuilderObject* self, PyObject* tag)
18671890
{
18681891
ElementObject *item;
18691892

1870-
if (self->data) {
1871-
if (self->this == self->last) {
1872-
Py_DECREF(JOIN_OBJ(self->last->text));
1873-
self->last->text = JOIN_SET(
1874-
self->data, PyList_CheckExact(self->data)
1875-
);
1876-
} else {
1877-
Py_DECREF(JOIN_OBJ(self->last->tail));
1878-
self->last->tail = JOIN_SET(
1879-
self->data, PyList_CheckExact(self->data)
1880-
);
1881-
}
1882-
self->data = NULL;
1883-
}
1893+
treebuilder_flush_data(self);
18841894

18851895
if (self->index == 0) {
18861896
PyErr_SetString(

0 commit comments

Comments
 (0)