Fix xpath_node_set assignment to provide strong exception guarantee
Since the type of the set was updated before assignment, assigning in out-of-memory condition could change the type to not match the content.
This commit is contained in:
parent
2badcbb674
commit
5158ee903b
@ -11025,7 +11025,7 @@ namespace pugi
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PUGI__FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_)
|
PUGI__FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_, type_t type_)
|
||||||
{
|
{
|
||||||
assert(begin_ <= end_);
|
assert(begin_ <= end_);
|
||||||
|
|
||||||
@ -11041,6 +11041,7 @@ namespace pugi
|
|||||||
|
|
||||||
_begin = &_storage;
|
_begin = &_storage;
|
||||||
_end = &_storage + size_;
|
_end = &_storage + size_;
|
||||||
|
_type = type_;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -11064,6 +11065,7 @@ namespace pugi
|
|||||||
// finalize
|
// finalize
|
||||||
_begin = storage;
|
_begin = storage;
|
||||||
_end = storage + size_;
|
_end = storage + size_;
|
||||||
|
_type = type_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11071,9 +11073,9 @@ namespace pugi
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_), _begin(&_storage), _end(&_storage)
|
PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_unsorted), _begin(&_storage), _end(&_storage)
|
||||||
{
|
{
|
||||||
_assign(begin_, end_);
|
_assign(begin_, end_, type_);
|
||||||
}
|
}
|
||||||
|
|
||||||
PUGI__FN xpath_node_set::~xpath_node_set()
|
PUGI__FN xpath_node_set::~xpath_node_set()
|
||||||
@ -11081,17 +11083,16 @@ namespace pugi
|
|||||||
if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
|
if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(ns._type), _begin(&_storage), _end(&_storage)
|
PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(&_storage), _end(&_storage)
|
||||||
{
|
{
|
||||||
_assign(ns._begin, ns._end);
|
_assign(ns._begin, ns._end, ns._type);
|
||||||
}
|
}
|
||||||
|
|
||||||
PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns)
|
PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns)
|
||||||
{
|
{
|
||||||
if (this == &ns) return *this;
|
if (this == &ns) return *this;
|
||||||
|
|
||||||
_type = ns._type;
|
_assign(ns._begin, ns._end, ns._type);
|
||||||
_assign(ns._begin, ns._end);
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1286,7 +1286,7 @@ namespace pugi
|
|||||||
xpath_node* _begin;
|
xpath_node* _begin;
|
||||||
xpath_node* _end;
|
xpath_node* _end;
|
||||||
|
|
||||||
void _assign(const_iterator begin, const_iterator end);
|
void _assign(const_iterator begin, const_iterator end, type_t type);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -381,15 +381,20 @@ TEST_XML(xpath_api_node_set_assign_out_of_memory_preserve, "<node><a/><b/></node
|
|||||||
{
|
{
|
||||||
xpath_node_set ns = doc.select_nodes(STR("node/*"));
|
xpath_node_set ns = doc.select_nodes(STR("node/*"));
|
||||||
CHECK(ns.size() == 2);
|
CHECK(ns.size() == 2);
|
||||||
|
CHECK(ns.type() == xpath_node_set::type_sorted);
|
||||||
|
|
||||||
xpath_node_set nsall = doc.select_nodes(STR("//*"));
|
xpath_node_set nsall = doc.select_nodes(STR("//*"));
|
||||||
|
nsall.sort(true);
|
||||||
CHECK(nsall.size() == 3);
|
CHECK(nsall.size() == 3);
|
||||||
|
CHECK(nsall.type() == xpath_node_set::type_sorted_reverse);
|
||||||
|
|
||||||
test_runner::_memory_fail_threshold = 1;
|
test_runner::_memory_fail_threshold = 1;
|
||||||
|
|
||||||
CHECK_ALLOC_FAIL(ns = nsall);
|
CHECK_ALLOC_FAIL(ns = nsall);
|
||||||
|
|
||||||
CHECK(ns.size() == 2 && ns[0] == doc.child(STR("node")).child(STR("a")) && ns[1] == doc.child(STR("node")).child(STR("b")));
|
CHECK(ns.size() == 2);
|
||||||
|
CHECK(ns.type() == xpath_node_set::type_sorted);
|
||||||
|
CHECK(ns[0] == doc.child(STR("node")).child(STR("a")) && ns[1] == doc.child(STR("node")).child(STR("b")));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_XML(xpath_api_deprecated_select_single_node, "<node><head/><foo id='1'/><foo/><tail/></node>")
|
TEST_XML(xpath_api_deprecated_select_single_node, "<node><head/><foo id='1'/><foo/><tail/></node>")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user