Skip to content

Commit c8d8e15

Browse files
scoderserhiy-storchaka
authored andcommitted
bpo-31455: Fix an assertion failure in ElementTree.XMLParser(). (#3545)
* 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.
1 parent 0b3a87e commit c8d8e15

File tree

3 files changed

+60
-2
lines changed

3 files changed

+60
-2
lines changed

Lib/test/test_xml_etree.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2498,6 +2498,31 @@ def close(self):
24982498
('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
24992499
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
25002500

2501+
def test_builder_lookup_errors(self):
2502+
class RaisingBuilder:
2503+
def __init__(self, raise_in=None, what=ValueError):
2504+
self.raise_in = raise_in
2505+
self.what = what
2506+
2507+
def __getattr__(self, name):
2508+
if name == self.raise_in:
2509+
raise self.what(self.raise_in)
2510+
def handle(*args):
2511+
pass
2512+
return handle
2513+
2514+
ET.XMLParser(target=RaisingBuilder())
2515+
# cET also checks for 'close' and 'doctype', PyET does it only at need
2516+
for event in ('start', 'data', 'end', 'comment', 'pi'):
2517+
with self.assertRaisesRegex(ValueError, event):
2518+
ET.XMLParser(target=RaisingBuilder(event))
2519+
2520+
ET.XMLParser(target=RaisingBuilder(what=AttributeError))
2521+
for event in ('start', 'data', 'end', 'comment', 'pi'):
2522+
parser = ET.XMLParser(target=RaisingBuilder(event, what=AttributeError))
2523+
parser.feed(self.sample1)
2524+
self.assertIsNone(parser.close())
2525+
25012526

25022527
class XMLParserTest(unittest.TestCase):
25032528
sample1 = b'<file><line>22</line></file>'
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The C accelerator module of ElementTree ignored exceptions raised when
2+
looking up TreeBuilder target methods in XMLParser().

Modules/_elementtree.c

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3260,6 +3260,18 @@ xmlparser_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
32603260
return (PyObject *)self;
32613261
}
32623262

3263+
static int
3264+
ignore_attribute_error(PyObject *value)
3265+
{
3266+
if (value == NULL) {
3267+
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
3268+
return -1;
3269+
}
3270+
PyErr_Clear();
3271+
}
3272+
return 0;
3273+
}
3274+
32633275
/*[clinic input]
32643276
_elementtree.XMLParser.__init__
32653277
@@ -3314,14 +3326,33 @@ _elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *html,
33143326
self->target = target;
33153327

33163328
self->handle_start = PyObject_GetAttrString(target, "start");
3329+
if (ignore_attribute_error(self->handle_start)) {
3330+
return -1;
3331+
}
33173332
self->handle_data = PyObject_GetAttrString(target, "data");
3333+
if (ignore_attribute_error(self->handle_data)) {
3334+
return -1;
3335+
}
33183336
self->handle_end = PyObject_GetAttrString(target, "end");
3337+
if (ignore_attribute_error(self->handle_end)) {
3338+
return -1;
3339+
}
33193340
self->handle_comment = PyObject_GetAttrString(target, "comment");
3341+
if (ignore_attribute_error(self->handle_comment)) {
3342+
return -1;
3343+
}
33203344
self->handle_pi = PyObject_GetAttrString(target, "pi");
3345+
if (ignore_attribute_error(self->handle_pi)) {
3346+
return -1;
3347+
}
33213348
self->handle_close = PyObject_GetAttrString(target, "close");
3349+
if (ignore_attribute_error(self->handle_close)) {
3350+
return -1;
3351+
}
33223352
self->handle_doctype = PyObject_GetAttrString(target, "doctype");
3323-
3324-
PyErr_Clear();
3353+
if (ignore_attribute_error(self->handle_doctype)) {
3354+
return -1;
3355+
}
33253356

33263357
/* configure parser */
33273358
EXPAT(SetUserData)(self->parser, self);

0 commit comments

Comments
 (0)