From 85add4783ef9c7bc459638bb36f1172ed6a18ba6 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 21 Dec 2016 12:55:28 +0200 Subject: [PATCH] Issue #28871: Fixed a crash when deallocate deep ElementTree. Fixed running MiscTests in test_xml_etree_c. --- Lib/test/test_xml_etree_c.py | 11 +++++++++++ Misc/NEWS | 2 ++ Modules/_elementtree.c | 23 +++++++++++++++++++---- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py index 98410c55a66e..8d9bd17a19a6 100644 --- a/Lib/test/test_xml_etree_c.py +++ b/Lib/test/test_xml_etree_c.py @@ -17,6 +17,7 @@ def sanity(): """ +@unittest.skipUnless(cET, 'requires _elementtree') class MiscTests(unittest.TestCase): # Issue #8651. @precisionbigmemtest(size=_2G + 100, memuse=1) @@ -62,12 +63,22 @@ class MiscTests(unittest.TestCase): del element.attrib self.assertEqual(element.attrib, {'A': 'B', 'C': 'D'}) + def test_trashcan(self): + # If this test fails, it will most likely die via segfault. + e = root = cET.Element('root') + for i in range(200000): + e = cET.SubElement(e, 'x') + del e + del root + test_support.gc_collect() + def test_main(): from test import test_xml_etree, test_xml_etree_c # Run the tests specific to the C implementation test_support.run_doctest(test_xml_etree_c, verbosity=True) + test_support.run_unittest(MiscTests) # Assign the C implementation before running the doctests # Patch the __name__, to prevent confusion with the pure Python test diff --git a/Misc/NEWS b/Misc/NEWS index b6474eb33369..9f749f424166 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,8 @@ Library - Issue #29019: Fix dict.fromkeys(x) overallocates when x is sparce dict. Original patch by Rasmus Villemoes. +- Issue #28871: Fixed a crash when deallocate deep ElementTree. + - Issue #19542: Fix bugs in WeakValueDictionary.setdefault() and WeakValueDictionary.pop() when a GC collection happens in another thread. diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index b01167b8a08e..8e5b5877030a 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -121,6 +121,18 @@ typedef int Py_ssize_t; #define JOIN_SET(p, flag) ((void*) ((Py_uintptr_t) (JOIN_OBJ(p)) | (flag))) #define JOIN_OBJ(p) ((PyObject*) ((Py_uintptr_t) (p) & ~1)) +/* Py_CLEAR for a PyObject* that uses a join flag. Pass the pointer by + * reference since this function sets it to NULL. +*/ +static void _clear_joined_ptr(PyObject **p) +{ + if (*p) { + PyObject *tmp = JOIN_OBJ(*p); + *p = NULL; + Py_DECREF(tmp); + } +} + /* glue functions (see the init function for details) */ static PyObject* elementtree_parseerror_obj; static PyObject* elementtree_copyelement_obj; @@ -538,17 +550,20 @@ subelement(PyObject* self, PyObject* args, PyObject* kw) static void element_dealloc(ElementObject* self) { - if (self->extra) - element_dealloc_extra(self); + Py_TRASHCAN_SAFE_BEGIN(self) /* discard attributes */ Py_DECREF(self->tag); - Py_DECREF(JOIN_OBJ(self->text)); - Py_DECREF(JOIN_OBJ(self->tail)); + _clear_joined_ptr(&self->text); + _clear_joined_ptr(&self->tail); + + if (self->extra) + element_dealloc_extra(self); RELEASE(sizeof(ElementObject), "destroy element"); PyObject_Del(self); + Py_TRASHCAN_SAFE_END(self) } /* -------------------------------------------------------------------- */ -- 2.47.3