aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArseny Kapoulkine <arseny.kapoulkine@gmail.com>2018-09-24 20:18:12 -0700
committerArseny Kapoulkine <arseny.kapoulkine@gmail.com>2018-09-24 20:19:31 -0700
commite3b5e9ce3c51f5015d94d848903a23374fb90473 (patch)
treed9da81e9cd35445d4e05b187260aebbe929d6401
parent1a96777b1142f8496c38f91d22a4587f2f6dd26f (diff)
downloadpugixml-e3b5e9ce3c51f5015d94d848903a23374fb90473.zip
pugixml-e3b5e9ce3c51f5015d94d848903a23374fb90473.tar.gz
pugixml-e3b5e9ce3c51f5015d94d848903a23374fb90473.tar.bz2
XPath: Refactor xpath_node_set short buffer optimization
This change replaces xpath_node_set single element storage with a single-element array in hopes that this would silence Coverity false positive about getting a singleton pointer. Additionally, it refactors _assign member to unify small and large buffer codepaths since they are basically identical. Fixes #233 (hopefully)
-rw-r--r--src/pugixml.cpp67
-rw-r--r--src/pugixml.hpp2
2 files changed, 28 insertions, 41 deletions
diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index b811ba7..e8a9daa 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -12013,74 +12013,61 @@ namespace pugi
size_t size_ = static_cast<size_t>(end_ - begin_);
- if (size_ <= 1)
- {
- // deallocate old buffer
- if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
-
- // use internal buffer
- if (begin_ != end_) _storage = *begin_;
+ // use internal buffer for 0 or 1 elements, heap buffer otherwise
+ xpath_node* storage = (size_ <= 1) ? _storage : static_cast<xpath_node*>(impl::xml_memory::allocate(size_ * sizeof(xpath_node)));
- _begin = &_storage;
- _end = &_storage + size_;
- _type = type_;
- }
- else
+ if (!storage)
{
- // make heap copy
- xpath_node* storage = static_cast<xpath_node*>(impl::xml_memory::allocate(size_ * sizeof(xpath_node)));
+ #ifdef PUGIXML_NO_EXCEPTIONS
+ return;
+ #else
+ throw std::bad_alloc();
+ #endif
+ }
- if (!storage)
- {
- #ifdef PUGIXML_NO_EXCEPTIONS
- return;
- #else
- throw std::bad_alloc();
- #endif
- }
+ // deallocate old buffer
+ if (_begin != _storage)
+ impl::xml_memory::deallocate(_begin);
+ // size check is necessary because for begin_ = end_ = nullptr, memcpy is UB
+ if (size_)
memcpy(storage, begin_, size_ * sizeof(xpath_node));
- // deallocate old buffer
- if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
-
- // finalize
- _begin = storage;
- _end = storage + size_;
- _type = type_;
- }
+ _begin = storage;
+ _end = storage + size_;
+ _type = type_;
}
#ifdef PUGIXML_HAS_MOVE
PUGI__FN void xpath_node_set::_move(xpath_node_set& rhs) PUGIXML_NOEXCEPT
{
_type = rhs._type;
- _storage = rhs._storage;
- _begin = (rhs._begin == &rhs._storage) ? &_storage : rhs._begin;
+ _storage[0] = rhs._storage[0];
+ _begin = (rhs._begin == rhs._storage) ? _storage : rhs._begin;
_end = _begin + (rhs._end - rhs._begin);
rhs._type = type_unsorted;
- rhs._begin = &rhs._storage;
- rhs._end = rhs._begin;
+ rhs._begin = rhs._storage;
+ rhs._end = rhs._storage;
}
#endif
- PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(&_storage), _end(&_storage)
+ PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _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)
+ 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_, type_);
}
PUGI__FN xpath_node_set::~xpath_node_set()
{
- if (_begin != &_storage)
+ if (_begin != _storage)
impl::xml_memory::deallocate(_begin);
}
- PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _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, ns._type);
}
@@ -12095,7 +12082,7 @@ namespace pugi
}
#ifdef PUGIXML_HAS_MOVE
- PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT: _type(type_unsorted), _begin(&_storage), _end(&_storage)
+ PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT: _type(type_unsorted), _begin(_storage), _end(_storage)
{
_move(rhs);
}
@@ -12104,7 +12091,7 @@ namespace pugi
{
if (this == &rhs) return *this;
- if (_begin != &_storage)
+ if (_begin != _storage)
impl::xml_memory::deallocate(_begin);
_move(rhs);
diff --git a/src/pugixml.hpp b/src/pugixml.hpp
index 19ace6e..5c928f5 100644
--- a/src/pugixml.hpp
+++ b/src/pugixml.hpp
@@ -1372,7 +1372,7 @@ namespace pugi
private:
type_t _type;
- xpath_node _storage;
+ xpath_node _storage[1];
xpath_node* _begin;
xpath_node* _end;