[3.6] bpo-31455: Fix an assertion failure in ElementTree.XMLParser(). (GH-3545) (#3585)
* 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 c8d8e15bfc
)
This commit is contained in:
parent
1658ec0757
commit
49caab46f6
|
@ -2476,6 +2476,31 @@ class TreeBuilderTest(unittest.TestCase):
|
||||||
('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
|
('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
|
||||||
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
|
'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):
|
class XMLParserTest(unittest.TestCase):
|
||||||
sample1 = b'<file><line>22</line></file>'
|
sample1 = b'<file><line>22</line></file>'
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
The C accelerator module of ElementTree ignored exceptions raised when
|
||||||
|
looking up TreeBuilder target methods in XMLParser().
|
|
@ -3224,6 +3224,18 @@ xmlparser_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
return (PyObject *)self;
|
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]
|
/*[clinic input]
|
||||||
_elementtree.XMLParser.__init__
|
_elementtree.XMLParser.__init__
|
||||||
|
|
||||||
|
@ -3270,14 +3282,33 @@ _elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *html,
|
||||||
self->target = target;
|
self->target = target;
|
||||||
|
|
||||||
self->handle_start = PyObject_GetAttrString(target, "start");
|
self->handle_start = PyObject_GetAttrString(target, "start");
|
||||||
|
if (ignore_attribute_error(self->handle_start)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
self->handle_data = PyObject_GetAttrString(target, "data");
|
self->handle_data = PyObject_GetAttrString(target, "data");
|
||||||
|
if (ignore_attribute_error(self->handle_data)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
self->handle_end = PyObject_GetAttrString(target, "end");
|
self->handle_end = PyObject_GetAttrString(target, "end");
|
||||||
|
if (ignore_attribute_error(self->handle_end)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
self->handle_comment = PyObject_GetAttrString(target, "comment");
|
self->handle_comment = PyObject_GetAttrString(target, "comment");
|
||||||
|
if (ignore_attribute_error(self->handle_comment)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
self->handle_pi = PyObject_GetAttrString(target, "pi");
|
self->handle_pi = PyObject_GetAttrString(target, "pi");
|
||||||
|
if (ignore_attribute_error(self->handle_pi)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
self->handle_close = PyObject_GetAttrString(target, "close");
|
self->handle_close = PyObject_GetAttrString(target, "close");
|
||||||
|
if (ignore_attribute_error(self->handle_close)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
self->handle_doctype = PyObject_GetAttrString(target, "doctype");
|
self->handle_doctype = PyObject_GetAttrString(target, "doctype");
|
||||||
|
if (ignore_attribute_error(self->handle_doctype)) {
|
||||||
PyErr_Clear();
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* configure parser */
|
/* configure parser */
|
||||||
EXPAT(SetUserData)(self->parser, self);
|
EXPAT(SetUserData)(self->parser, self);
|
||||||
|
|
Loading…
Reference in New Issue