Skip to content

Commit d15cdb2

Browse files
bpo-27946: Fix possible crash in ElementTree.Element (pythonGH-29915)
Getting an attribute via attrib.get() simultaneously with replacing the attrib dict can lead to access to deallocated dict.
1 parent f42a06b commit d15cdb2

File tree

3 files changed

+25
-13
lines changed

3 files changed

+25
-13
lines changed

Lib/test/test_xml_etree_c.py

+12
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,18 @@ def test_xmlpullparser_leaks(self):
169169
del parser
170170
support.gc_collect()
171171

172+
def test_dict_disappearing_during_get_item(self):
173+
# test fix for seg fault reported in issue 27946
174+
class X:
175+
def __hash__(self):
176+
e.attrib = {} # this frees e->extra->attrib
177+
[{i: i} for i in range(1000)] # exhaust the dict keys cache
178+
return 13
179+
180+
e = cET.Element("elem", {1: 2})
181+
r = e.get(X())
182+
self.assertIsNone(r)
183+
172184

173185
@unittest.skipUnless(cET, 'requires _elementtree')
174186
class TestAliasWorking(unittest.TestCase):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix possible crash when getting an attribute of
2+
class:`xml.etree.ElementTree.Element` simultaneously with
3+
replacing the ``attrib`` dict.

Modules/_elementtree.c

+10-13
Original file line numberDiff line numberDiff line change
@@ -1393,22 +1393,19 @@ _elementtree_Element_get_impl(ElementObject *self, PyObject *key,
13931393
PyObject *default_value)
13941394
/*[clinic end generated code: output=523c614142595d75 input=ee153bbf8cdb246e]*/
13951395
{
1396-
PyObject* value;
1397-
1398-
if (!self->extra || !self->extra->attrib)
1399-
value = default_value;
1400-
else {
1401-
value = PyDict_GetItemWithError(self->extra->attrib, key);
1402-
if (!value) {
1403-
if (PyErr_Occurred()) {
1404-
return NULL;
1405-
}
1406-
value = default_value;
1396+
if (self->extra && self->extra->attrib) {
1397+
PyObject *attrib = self->extra->attrib;
1398+
Py_INCREF(attrib);
1399+
PyObject *value = PyDict_GetItemWithError(attrib, key);
1400+
Py_XINCREF(value);
1401+
Py_DECREF(attrib);
1402+
if (value != NULL || PyErr_Occurred()) {
1403+
return value;
14071404
}
14081405
}
14091406

1410-
Py_INCREF(value);
1411-
return value;
1407+
Py_INCREF(default_value);
1408+
return default_value;
14121409
}
14131410

14141411
static PyObject *

0 commit comments

Comments
 (0)