summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2014-08-28 14:19:25 +0200
committerStefan Behnel <stefan_ml@behnel.de>2014-08-28 14:19:25 +0200
commit11589fcf5b28101ec7b8de286ad0133a4894f83c (patch)
tree5b337001a289ac7da00e633cba94521d76a04d3b /src
parentd4f06ac0703961cc4a88504369aff5a5465b7561 (diff)
downloadpython-lxml-11589fcf5b28101ec7b8de286ad0133a4894f83c.tar.gz
fix crash when deallocating sibling Element proxies that do not have a parent
Diffstat (limited to 'src')
-rw-r--r--src/lxml/proxy.pxi19
-rw-r--r--src/lxml/tests/test_etree.py31
2 files changed, 47 insertions, 3 deletions
diff --git a/src/lxml/proxy.pxi b/src/lxml/proxy.pxi
index 52909f69..e3b78165 100644
--- a/src/lxml/proxy.pxi
+++ b/src/lxml/proxy.pxi
@@ -167,6 +167,7 @@ cdef int attemptDeallocation(xmlNode* c_node):
cdef xmlNode* getDeallocationTop(xmlNode* c_node):
u"""Return the top of the tree that can be deallocated, or NULL.
"""
+ cdef xmlNode* c_next
#print "trying to do deallocating:", c_node.type
if hasProxy(c_node):
#print "Not freeing: proxies still exist"
@@ -183,10 +184,22 @@ cdef xmlNode* getDeallocationTop(xmlNode* c_node):
#print "Not freeing: proxies still exist"
return NULL
# see whether we have children to deallocate
- if canDeallocateChildNodes(c_node):
- return c_node
- else:
+ if not canDeallocateChildNodes(c_node):
return NULL
+ # see whether we have siblings to deallocate
+ c_next = c_node.prev
+ while c_next:
+ if _isElement(c_next):
+ if hasProxy(c_next) or not canDeallocateChildNodes(c_next):
+ return NULL
+ c_next = c_next.prev
+ c_next = c_node.next
+ while c_next:
+ if _isElement(c_next):
+ if hasProxy(c_next) or not canDeallocateChildNodes(c_next):
+ return NULL
+ c_next = c_next.next
+ return c_node
cdef int canDeallocateChildNodes(xmlNode* c_parent):
cdef xmlNode* c_node
diff --git a/src/lxml/tests/test_etree.py b/src/lxml/tests/test_etree.py
index 41d6571f..132e2ce9 100644
--- a/src/lxml/tests/test_etree.py
+++ b/src/lxml/tests/test_etree.py
@@ -3557,6 +3557,37 @@ class ETreeOnlyTestCase(HelperTestCase):
gc.collect()
# not really testing anything here, but it shouldn't crash
+ def test_proxy_collect_siblings(self):
+ root = etree.Element('parent')
+ c1 = etree.SubElement(root, 'child1')
+ c2 = etree.SubElement(root, 'child2')
+
+ root.remove(c1)
+ root.remove(c2)
+ c1.addnext(c2)
+ del c1
+ # trigger deallocation attempt of c1
+ c2.getprevious()
+ # make sure it wasn't deallocated
+ self.assertEqual('child1', c2.getprevious().tag)
+
+ def test_proxy_collect_siblings_text(self):
+ root = etree.Element('parent')
+ c1 = etree.SubElement(root, 'child1')
+ c2 = etree.SubElement(root, 'child2')
+
+ root.remove(c1)
+ root.remove(c2)
+ c1.addnext(c2)
+ c1.tail = 'abc'
+ c2.tail = 'xyz'
+ del c1
+ # trigger deallocation attempt of c1
+ c2.getprevious()
+ # make sure it wasn't deallocated
+ self.assertEqual('child1', c2.getprevious().tag)
+ self.assertEqual('abc', c2.getprevious().tail)
+
# helper methods
def _writeElement(self, element, encoding='us-ascii', compression=0):