diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py index 270b9d6da8e7b9..e9aed652c2a056 100644 --- a/Lib/test/test_xml_etree_c.py +++ b/Lib/test/test_xml_etree_c.py @@ -1,6 +1,7 @@ # xml.etree test for cElementTree import io import struct +import sys from test import support from test.support.import_helper import import_fresh_module import types @@ -171,6 +172,20 @@ def test_xmlpullparser_leaks(self): del parser support.gc_collect() + @support.refcount_test + def test_xmlparser_refleaks_in___init__(self): + gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount') + parser = cET.XMLParser() + lastrc = gettotalrefcount() + for i in range(20): + support.gc_collect() + rc = gettotalrefcount() + for _ in range(100): + parser.__init__() + delta = rc - lastrc + lastrc = rc + self.assertLess(delta, 3) + def test_dict_disappearing_during_get_item(self): # test fix for seg fault reported in issue 27946 class X: diff --git a/Misc/NEWS.d/next/Library/2026-04-04-00-37-39.gh-issue-148058.zMIVaS.rst b/Misc/NEWS.d/next/Library/2026-04-04-00-37-39.gh-issue-148058.zMIVaS.rst new file mode 100644 index 00000000000000..20b9f36bfe2d2c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-04-00-37-39.gh-issue-148058.zMIVaS.rst @@ -0,0 +1,3 @@ +Fix reference leak in :class:`xml.etree.ElementTree.XMLParser` when +:meth:`~object.__init__` is called many times. Patch by Maurycy +Pawłowski-Wieroński. diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index e2185c4bd03aad..9b0dea741aba7e 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -3699,6 +3699,8 @@ ignore_attribute_error(PyObject *value) return 0; } +static int xmlparser_gc_clear(PyObject *op); + /*[clinic input] _elementtree.XMLParser.__init__ @@ -3713,6 +3715,10 @@ _elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *target, const char *encoding) /*[clinic end generated code: output=3ae45ec6cdf344e4 input=7e716dd6e4f3e439]*/ { + if (self->parser != NULL) { + (void)xmlparser_gc_clear((PyObject *)self); + } + self->entity = PyDict_New(); if (!self->entity) return -1;