0
0
mirror of https://github.com/zeux/pugixml.git synced 2025-01-14 01:47:55 +08:00

Adjust node_copy_tree to be more explicit about invariants

The loop traverses the source tree and simultaneously builds up a copy
of it at destination. Short of race conditions, this code is safe -
however, it's not obvious that dit stays inside the destination tree.

This change adds a few assertions to help enforce/document these
invariants. One particular subtlety is that dit can actually *become*
null after we exit out of the loop, but it's guaranteed to only do so
once sit goes back to sn.

This is only possible when doing a full document copy - for some reason
we weren't using this for that (in reset(xml_document)), but we are now.

Fixes #314.
This commit is contained in:
Arseny Kapoulkine 2020-02-19 20:55:04 -08:00
parent 76c3914484
commit 5e64076af9

View File

@ -4435,6 +4435,9 @@ PUGI__NS_BEGIN
while (sit && sit != sn) while (sit && sit != sn)
{ {
// loop invariant: dit is inside the subtree rooted at dn
assert(dit);
// when a tree is copied into one of the descendants, we need to skip that subtree to avoid an infinite loop // when a tree is copied into one of the descendants, we need to skip that subtree to avoid an infinite loop
if (sit != dn) if (sit != dn)
{ {
@ -4464,9 +4467,14 @@ PUGI__NS_BEGIN
sit = sit->parent; sit = sit->parent;
dit = dit->parent; dit = dit->parent;
// loop invariant: dit is inside the subtree rooted at dn while sit is inside sn
assert(sit == sn || dit);
} }
while (sit != sn); while (sit != sn);
} }
assert(!sit || dit == dn->parent);
} }
PUGI__FN void node_copy_attribute(xml_attribute_struct* da, xml_attribute_struct* sa) PUGI__FN void node_copy_attribute(xml_attribute_struct* da, xml_attribute_struct* sa)
@ -6949,8 +6957,7 @@ namespace pugi
{ {
reset(); reset();
for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling()) impl::node_copy_tree(_root, proto._root);
append_copy(cur);
} }
PUGI__FN void xml_document::_create() PUGI__FN void xml_document::_create()