[3.6] bpo-31499, xml.etree: Fix xmlparser_gc_clear() crash (GH-3641) (#3645)
* bpo-31499, xml.etree: Fix xmlparser_gc_clear() crash
xml.etree: xmlparser_gc_clear() now sets self.parser to NULL to prevent a
crash in xmlparser_dealloc() if xmlparser_gc_clear() was called previously
by the garbage collector, because the parser was part of a reference cycle.
Co-Authored-By: Serhiy Storchaka <storchaka@gmail.com>
(cherry picked from commit e727d41ffc
)
This commit is contained in:
parent
84c89ef4e5
commit
8afd7ab12d
|
@ -64,6 +64,26 @@ class MiscTests(unittest.TestCase):
|
||||||
del root
|
del root
|
||||||
support.gc_collect()
|
support.gc_collect()
|
||||||
|
|
||||||
|
def test_parser_ref_cycle(self):
|
||||||
|
# bpo-31499: xmlparser_dealloc() crashed with a segmentation fault when
|
||||||
|
# xmlparser_gc_clear() was called previously by the garbage collector,
|
||||||
|
# when the parser was part of a reference cycle.
|
||||||
|
|
||||||
|
def parser_ref_cycle():
|
||||||
|
parser = cET.XMLParser()
|
||||||
|
# Create a reference cycle using an exception to keep the frame
|
||||||
|
# alive, so the parser will be destroyed by the garbage collector
|
||||||
|
try:
|
||||||
|
raise ValueError
|
||||||
|
except ValueError as exc:
|
||||||
|
err = exc
|
||||||
|
|
||||||
|
# Create a parser part of reference cycle
|
||||||
|
parser_ref_cycle()
|
||||||
|
# Trigger an explicit garbage collection to break the reference cycle
|
||||||
|
# and so destroy the parser
|
||||||
|
support.gc_collect()
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(cET, 'requires _elementtree')
|
@unittest.skipUnless(cET, 'requires _elementtree')
|
||||||
class TestAliasWorking(unittest.TestCase):
|
class TestAliasWorking(unittest.TestCase):
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
xml.etree: Fix a crash when a parser is part of a reference cycle.
|
|
@ -3367,7 +3367,11 @@ xmlparser_gc_traverse(XMLParserObject *self, visitproc visit, void *arg)
|
||||||
static int
|
static int
|
||||||
xmlparser_gc_clear(XMLParserObject *self)
|
xmlparser_gc_clear(XMLParserObject *self)
|
||||||
{
|
{
|
||||||
EXPAT(ParserFree)(self->parser);
|
if (self->parser != NULL) {
|
||||||
|
XML_Parser parser = self->parser;
|
||||||
|
self->parser = NULL;
|
||||||
|
EXPAT(ParserFree)(parser);
|
||||||
|
}
|
||||||
|
|
||||||
Py_CLEAR(self->handle_close);
|
Py_CLEAR(self->handle_close);
|
||||||
Py_CLEAR(self->handle_pi);
|
Py_CLEAR(self->handle_pi);
|
||||||
|
|
Loading…
Reference in New Issue