diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2017-09-18 12:29:37 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-18 12:29:37 (GMT) |
commit | e727d41ffcd91b21ce82026ec8c8381d34a16209 (patch) | |
tree | 6fe96261c5baf6fe58a218c6c1d3649d931c8606 | |
parent | 9b47af65375fab9318e88ccb061394a36c8c6c33 (diff) | |
download | cpython-e727d41ffcd91b21ce82026ec8c8381d34a16209.zip cpython-e727d41ffcd91b21ce82026ec8c8381d34a16209.tar.gz cpython-e727d41ffcd91b21ce82026ec8c8381d34a16209.tar.bz2 |
bpo-31499, xml.etree: Fix xmlparser_gc_clear() crash (#3641)
* 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>
-rw-r--r-- | Lib/test/test_xml_etree_c.py | 20 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2017-09-18-10-57-04.bpo-31499.BydYhf.rst | 1 | ||||
-rw-r--r-- | Modules/_elementtree.c | 6 |
3 files changed, 26 insertions, 1 deletions
diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py index 171a3f8..25517a7 100644 --- a/Lib/test/test_xml_etree_c.py +++ b/Lib/test/test_xml_etree_c.py @@ -65,6 +65,26 @@ class MiscTests(unittest.TestCase): del root 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') class TestAliasWorking(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2017-09-18-10-57-04.bpo-31499.BydYhf.rst b/Misc/NEWS.d/next/Library/2017-09-18-10-57-04.bpo-31499.BydYhf.rst new file mode 100644 index 0000000..22af29f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-09-18-10-57-04.bpo-31499.BydYhf.rst @@ -0,0 +1 @@ +xml.etree: Fix a crash when a parser is part of a reference cycle. diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index 28d0181..bddac85 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -3411,7 +3411,11 @@ xmlparser_gc_traverse(XMLParserObject *self, visitproc visit, void *arg) static int 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_pi); |