]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-27946: Fix possible crash in ElementTree.Element (GH-29915)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Sun, 5 Dec 2021 19:04:59 +0000 (11:04 -0800)
committerGitHub <noreply@github.com>
Sun, 5 Dec 2021 19:04:59 +0000 (11:04 -0800)
Getting an attribute via attrib.get() simultaneously with replacing
the attrib dict can lead to access to deallocated dict.
(cherry picked from commit d15cdb2f32f572ce56d7120135da24b9fdce4c99)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Lib/test/test_xml_etree_c.py
Misc/NEWS.d/next/Library/2021-12-04-20-08-42.bpo-27946.-Vuarf.rst [new file with mode: 0644]
Modules/_elementtree.c

index e26e1714a540bdb6647caaf671d9e63646b83105..82cedfd00a55da310a04f53fcb6d35a227ff3282 100644 (file)
@@ -169,6 +169,18 @@ class MiscTests(unittest.TestCase):
         del parser
         support.gc_collect()
 
+    def test_dict_disappearing_during_get_item(self):
+        # test fix for seg fault reported in issue 27946
+        class X:
+            def __hash__(self):
+                e.attrib = {} # this frees e->extra->attrib
+                [{i: i} for i in range(1000)] # exhaust the dict keys cache
+                return 13
+
+        e = cET.Element("elem", {1: 2})
+        r = e.get(X())
+        self.assertIsNone(r)
+
 
 @unittest.skipUnless(cET, 'requires _elementtree')
 class TestAliasWorking(unittest.TestCase):
diff --git a/Misc/NEWS.d/next/Library/2021-12-04-20-08-42.bpo-27946.-Vuarf.rst b/Misc/NEWS.d/next/Library/2021-12-04-20-08-42.bpo-27946.-Vuarf.rst
new file mode 100644 (file)
index 0000000..0378efc
--- /dev/null
@@ -0,0 +1,3 @@
+Fix possible crash when getting an attribute of
+class:`xml.etree.ElementTree.Element` simultaneously with
+replacing the ``attrib`` dict.
index 67a00a3413b1d8d3a550a83153be0a08dd31d05c..d9c2a23ccb8588e0b56c7c6e95a49e9811e9a3e9 100644 (file)
@@ -1393,22 +1393,19 @@ _elementtree_Element_get_impl(ElementObject *self, PyObject *key,
                               PyObject *default_value)
 /*[clinic end generated code: output=523c614142595d75 input=ee153bbf8cdb246e]*/
 {
-    PyObject* value;
-
-    if (!self->extra || !self->extra->attrib)
-        value = default_value;
-    else {
-        value = PyDict_GetItemWithError(self->extra->attrib, key);
-        if (!value) {
-            if (PyErr_Occurred()) {
-                return NULL;
-            }
-            value = default_value;
+    if (self->extra && self->extra->attrib) {
+        PyObject *attrib = self->extra->attrib;
+        Py_INCREF(attrib);
+        PyObject *value = PyDict_GetItemWithError(attrib, key);
+        Py_XINCREF(value);
+        Py_DECREF(attrib);
+        if (value != NULL || PyErr_Occurred()) {
+            return value;
         }
     }
 
-    Py_INCREF(value);
-    return value;
+    Py_INCREF(default_value);
+    return default_value;
 }
 
 static PyObject *