Skip to content

Commit 0694b6a

Browse files
scoderserhiy-storchaka
authored andcommitted
bpo-31544: Avoid calling "PyObject_GetAttrString()" (and potentially executing user code) with a live exception set. (GH-3992)
1 parent 1ce4e5b commit 0694b6a

File tree

3 files changed

+68
-2
lines changed

3 files changed

+68
-2
lines changed

Lib/test/test_xml_etree.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,13 @@ def wrapper(*args):
136136
return test(*args)
137137
return wrapper
138138

139+
def cet_only(test):
140+
def wrapper(*args):
141+
if ET is pyET:
142+
raise unittest.SkipTest('only for the C version')
143+
return test(*args)
144+
return wrapper
145+
139146
# --------------------------------------------------------------------
140147
# element tree tests
141148

@@ -2229,6 +2236,32 @@ def close(self):
22292236
('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
22302237
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
22312238

2239+
@cet_only # PyET does not look up the attributes in XMLParser().__init__()
2240+
def test_builder_lookup_errors(self):
2241+
class RaisingBuilder(object):
2242+
def __init__(self, raise_in=None, what=ValueError):
2243+
self.raise_in = raise_in
2244+
self.what = what
2245+
2246+
def __getattr__(self, name):
2247+
if name == self.raise_in:
2248+
raise self.what(self.raise_in)
2249+
def handle(*args):
2250+
pass
2251+
return handle
2252+
2253+
ET.XMLParser(target=RaisingBuilder())
2254+
# cET also checks for 'close' and 'doctype', PyET does it only at need
2255+
for event in ('start', 'data', 'end', 'comment', 'pi'):
2256+
with self.assertRaises(ValueError):
2257+
ET.XMLParser(target=RaisingBuilder(event))
2258+
2259+
ET.XMLParser(target=RaisingBuilder(what=AttributeError))
2260+
for event in ('start', 'data', 'end', 'comment', 'pi'):
2261+
parser = ET.XMLParser(target=RaisingBuilder(event, what=AttributeError))
2262+
parser.feed(self.sample1)
2263+
self.assertIsNone(parser.close())
2264+
22322265

22332266
class XMLParserTest(unittest.TestCase):
22342267
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
@@ -2510,6 +2510,18 @@ expat_unknown_encoding_handler(XMLParserObject *self, const XML_Char *name,
25102510
/* -------------------------------------------------------------------- */
25112511
/* constructor and destructor */
25122512

2513+
static int
2514+
ignore_attribute_error(PyObject *value)
2515+
{
2516+
if (value == NULL) {
2517+
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
2518+
return -1;
2519+
}
2520+
PyErr_Clear();
2521+
}
2522+
return 0;
2523+
}
2524+
25132525
static PyObject*
25142526
xmlparser(PyObject* self_, PyObject* args, PyObject* kw)
25152527
{
@@ -2578,14 +2590,33 @@ xmlparser(PyObject* self_, PyObject* args, PyObject* kw)
25782590
self->target = target;
25792591

25802592
self->handle_xml = PyObject_GetAttrString(target, "xml");
2593+
if (ignore_attribute_error(self->handle_xml)) {
2594+
return NULL;
2595+
}
25812596
self->handle_start = PyObject_GetAttrString(target, "start");
2597+
if (ignore_attribute_error(self->handle_start)) {
2598+
return NULL;
2599+
}
25822600
self->handle_data = PyObject_GetAttrString(target, "data");
2601+
if (ignore_attribute_error(self->handle_data)) {
2602+
return NULL;
2603+
}
25832604
self->handle_end = PyObject_GetAttrString(target, "end");
2605+
if (ignore_attribute_error(self->handle_end)) {
2606+
return NULL;
2607+
}
25842608
self->handle_comment = PyObject_GetAttrString(target, "comment");
2609+
if (ignore_attribute_error(self->handle_comment)) {
2610+
return NULL;
2611+
}
25852612
self->handle_pi = PyObject_GetAttrString(target, "pi");
2613+
if (ignore_attribute_error(self->handle_pi)) {
2614+
return NULL;
2615+
}
25862616
self->handle_close = PyObject_GetAttrString(target, "close");
2587-
2588-
PyErr_Clear();
2617+
if (ignore_attribute_error(self->handle_close)) {
2618+
return NULL;
2619+
}
25892620

25902621
/* configure parser */
25912622
EXPAT(SetUserData)(self->parser, self);

0 commit comments

Comments
 (0)