Skip to content

Commit a55e2f1

Browse files
committed
[3.14] pythongh-140593: Fix a memory leak in function my_ElementDeclHandler of pyexpat (pythonGH-140602)
Ensure that the memory allocated for the content model passed to `my_ElementDeclHandler` is freed in all error paths. (cherry picked from commit e34a5e3) Co-authored-by: Sebastian Pipping <[email protected]>
1 parent 46a3fd2 commit a55e2f1

File tree

3 files changed

+21
-1
lines changed

3 files changed

+21
-1
lines changed

Lib/test/test_pyexpat.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,23 @@ def test_change_size_2(self):
668668
parser.Parse(xml2, True)
669669
self.assertEqual(self.n, 4)
670670

671+
class ElementDeclHandlerTest(unittest.TestCase):
672+
def test_trigger_leak(self):
673+
# Unfixed, this test would leak the memory of the so-called
674+
# "content model" in function ``my_ElementDeclHandler`` of pyexpat.
675+
# See https://github.com/python/cpython/issues/140593.
676+
data = textwrap.dedent('''\
677+
<!DOCTYPE quotations SYSTEM "quotations.dtd" [
678+
<!ELEMENT root ANY>
679+
]>
680+
<root/>
681+
''').encode('UTF-8')
682+
683+
parser = expat.ParserCreate()
684+
parser.NotStandaloneHandler = lambda: 1.234 # arbitrary float
685+
parser.ElementDeclHandler = lambda _1, _2: None
686+
self.assertRaises(TypeError, parser.Parse, data, True)
687+
671688
class MalformedInputTest(unittest.TestCase):
672689
def test1(self):
673690
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`: Fix a memory leak that could affect users with
2+
:meth:`~xml.parsers.expat.xmlparser.ElementDeclHandler` set to a custom
3+
element declaration handler. Patch by Sebastian Pipping.

Modules/pyexpat.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ my_ElementDeclHandler(void *userData,
597597
PyObject *modelobj, *nameobj;
598598

599599
if (PyErr_Occurred())
600-
return;
600+
goto finally;
601601

602602
if (flush_character_buffer(self) < 0)
603603
goto finally;

0 commit comments

Comments
 (0)