]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.6] bpo-31455: Fix an assertion failure in ElementTree.XMLParser(). (GH-3545) ...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Thu, 14 Sep 2017 23:13:21 +0000 (16:13 -0700)
committerSerhiy Storchaka <storchaka@gmail.com>
Thu, 14 Sep 2017 23:13:21 +0000 (02:13 +0300)
* Avoid calling "PyObject_GetAttrString()" (and potentially executing user code) with a live exception set.

* Ignore only AttributeError on attribute lookups in ElementTree.XMLParser() and propagate all other exceptions.
(cherry picked from commit c8d8e15bfc24abeeaaf3d8be9073276b0c011cdf)

Lib/test/test_xml_etree.py
Misc/NEWS.d/next/Library/2017-09-13-19-55-35.bpo-31544.beTh6t.rst [new file with mode: 0644]
Modules/_elementtree.c

index 15af1fc53365b67dce78ff9d8f8a79e79f3b84ac..ad0ffb31aa49a0809f19625f249bdf20a02813ba 100644 (file)
@@ -2476,6 +2476,31 @@ class TreeBuilderTest(unittest.TestCase):
             ('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
              'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
 
+    def test_builder_lookup_errors(self):
+        class RaisingBuilder:
+            def __init__(self, raise_in=None, what=ValueError):
+                self.raise_in = raise_in
+                self.what = what
+
+            def __getattr__(self, name):
+                if name == self.raise_in:
+                    raise self.what(self.raise_in)
+                def handle(*args):
+                    pass
+                return handle
+
+        ET.XMLParser(target=RaisingBuilder())
+        # cET also checks for 'close' and 'doctype', PyET does it only at need
+        for event in ('start', 'data', 'end', 'comment', 'pi'):
+            with self.assertRaisesRegex(ValueError, event):
+                ET.XMLParser(target=RaisingBuilder(event))
+
+        ET.XMLParser(target=RaisingBuilder(what=AttributeError))
+        for event in ('start', 'data', 'end', 'comment', 'pi'):
+            parser = ET.XMLParser(target=RaisingBuilder(event, what=AttributeError))
+            parser.feed(self.sample1)
+            self.assertIsNone(parser.close())
+
 
 class XMLParserTest(unittest.TestCase):
     sample1 = b'<file><line>22</line></file>'
diff --git a/Misc/NEWS.d/next/Library/2017-09-13-19-55-35.bpo-31544.beTh6t.rst b/Misc/NEWS.d/next/Library/2017-09-13-19-55-35.bpo-31544.beTh6t.rst
new file mode 100644 (file)
index 0000000..9ea3599
--- /dev/null
@@ -0,0 +1,2 @@
+The C accelerator module of ElementTree ignored exceptions raised when
+looking up TreeBuilder target methods in XMLParser().
index ccf5e6a78fdab5e54d9259f89aacc90689f4f04c..cf3e687c8c69144a1aefa86bd0d11b19d837ea4d 100644 (file)
@@ -3224,6 +3224,18 @@ xmlparser_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     return (PyObject *)self;
 }
 
+static int
+ignore_attribute_error(PyObject *value)
+{
+    if (value == NULL) {
+        if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            return -1;
+        }
+        PyErr_Clear();
+    }
+    return 0;
+}
+
 /*[clinic input]
 _elementtree.XMLParser.__init__
 
@@ -3270,14 +3282,33 @@ _elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *html,
     self->target = target;
 
     self->handle_start = PyObject_GetAttrString(target, "start");
+    if (ignore_attribute_error(self->handle_start)) {
+        return -1;
+    }
     self->handle_data = PyObject_GetAttrString(target, "data");
+    if (ignore_attribute_error(self->handle_data)) {
+        return -1;
+    }
     self->handle_end = PyObject_GetAttrString(target, "end");
+    if (ignore_attribute_error(self->handle_end)) {
+        return -1;
+    }
     self->handle_comment = PyObject_GetAttrString(target, "comment");
+    if (ignore_attribute_error(self->handle_comment)) {
+        return -1;
+    }
     self->handle_pi = PyObject_GetAttrString(target, "pi");
+    if (ignore_attribute_error(self->handle_pi)) {
+        return -1;
+    }
     self->handle_close = PyObject_GetAttrString(target, "close");
+    if (ignore_attribute_error(self->handle_close)) {
+        return -1;
+    }
     self->handle_doctype = PyObject_GetAttrString(target, "doctype");
-
-    PyErr_Clear();
+    if (ignore_attribute_error(self->handle_doctype)) {
+        return -1;
+    }
 
     /* configure parser */
     EXPAT(SetUserData)(self->parser, self);