Skip to content

Commit d3dd837

Browse files
Fix crash in conv_content_model function in pyexpat
1 parent 0575ce9 commit d3dd837

File tree

3 files changed

+24
-1
lines changed

3 files changed

+24
-1
lines changed

Lib/test/test_pyexpat.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,20 @@ def test_trigger_leak(self):
701701
parser.ElementDeclHandler = lambda _1, _2: None
702702
self.assertRaises(TypeError, parser.Parse, data, True)
703703

704+
def test_deeply_nested_content_model(self):
705+
data = ('<!DOCTYPE root [\n<!ELEMENT root '
706+
+ '(a, ' * 200000 + 'a'
707+
+ ')' * 200000
708+
+ '>\n]>\n<root/>\n').encode('UTF-8')
709+
710+
parser = expat.ParserCreate()
711+
parser.ElementDeclHandler = lambda _1, _2: None
712+
# This shouldn't crash:
713+
try:
714+
parser.ParseFile(BytesIO(data))
715+
except RecursionError:
716+
pass
717+
704718
class MalformedInputTest(unittest.TestCase):
705719
def test1(self):
706720
xml = b"\0\r\n"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:mod:`xml.parsers.expat`: Fixed a crash caused by unbounded C recursion when
2+
converting deeply nested XML content models with
3+
:meth:`~xml.parsers.expat.xmlparser.ElementDeclHandler`.

Modules/pyexpat.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,10 @@ static PyObject *
607607
conv_content_model(XML_Content * const model,
608608
PyObject *(*conv_string)(void *))
609609
{
610+
if (Py_EnterRecursiveCall(" in conv_content_model")) {
611+
return NULL;
612+
}
613+
610614
PyObject *result = NULL;
611615
PyObject *children = PyTuple_New(model->numchildren);
612616
int i;
@@ -618,14 +622,16 @@ conv_content_model(XML_Content * const model,
618622
conv_string);
619623
if (child == NULL) {
620624
Py_XDECREF(children);
621-
return NULL;
625+
goto done;
622626
}
623627
PyTuple_SET_ITEM(children, i, child);
624628
}
625629
result = Py_BuildValue("(iiO&N)",
626630
model->type, model->quant,
627631
conv_string, model->name, children);
628632
}
633+
done:
634+
Py_LeaveRecursiveCall();
629635
return result;
630636
}
631637

0 commit comments

Comments
 (0)