Fixes possible pointer arithmetic past end position in indexed

This commit is contained in:
Hans Dembinski 2020-01-03 01:57:20 +01:00 committed by GitHub
parent 3dff0438ea
commit 87e757f9e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -132,8 +132,7 @@ public:
/// Access indices as an iterable range. /// Access indices as an iterable range.
index_view indices() const noexcept { index_view indices() const noexcept {
BOOST_ASSERT(iter_.indices_.hist_); BOOST_ASSERT(iter_.indices_.hist_);
return {iter_.indices_.data(), return {iter_.indices_.begin(), iter_.indices_.end()};
iter_.indices_.data() + iter_.indices_.hist_->rank()};
} }
/// Access current bin. /// Access current bin.
@ -239,18 +238,20 @@ public:
pointer operator->() noexcept { return pointer_proxy{operator*()}; } pointer operator->() noexcept { return pointer_proxy{operator*()}; }
iterator& operator++() { iterator& operator++() {
BOOST_ASSERT(indices_.hist_); BOOST_ASSERT(iter_ < indices_.hist_->end());
std::size_t stride = 1; const auto cbeg = indices_.begin();
auto c = indices_.begin(); auto c = cbeg;
++c->idx;
++iter_; ++iter_;
while (c->idx == c->end && (c != (indices_.end() - 1))) { ++c->idx;
c->idx = c->begin; if (c->idx < c->end) return *this;
iter_ -= (c->end - c->begin) * stride; while (c->idx == c->end) {
stride *= c->extent; iter_ += c->end_skip;
++c; if (++c == indices_.end()) return *this;
++c->idx; ++c->idx;
iter_ += stride; }
while (c-- != cbeg) {
c->idx = c->begin;
iter_ += c->begin_skip;
} }
return *this; return *this;
} }
@ -264,52 +265,70 @@ public:
bool operator==(const iterator& x) const noexcept { return iter_ == x.iter_; } bool operator==(const iterator& x) const noexcept { return iter_ == x.iter_; }
bool operator!=(const iterator& x) const noexcept { return !operator==(x); } bool operator!=(const iterator& x) const noexcept { return !operator==(x); }
// make iterator ready for C++17 sentinels
bool operator==(const value_iterator& x) const noexcept { return iter_ == x; }
bool operator!=(const value_iterator& x) const noexcept { return !operator==(x); }
// useful for iterator debugging
std::size_t offset() const noexcept { return iter_ - indices_.hist_->begin(); }
private: private:
iterator(histogram_type* h) : iter_(h->begin()), indices_(h) {} iterator(value_iterator i, histogram_type& h) : iter_(i), indices_(&h) {}
value_iterator iter_; value_iterator iter_;
struct index_data { struct index_data {
axis::index_type idx, begin, end, extent; axis::index_type idx, begin, end;
std::size_t begin_skip, end_skip;
}; };
struct indices_t : std::array<index_data, buffer_size> { struct indices_t : private std::array<index_data, buffer_size> {
using base_type = std::array<index_data, buffer_size>; using base_type = std::array<index_data, buffer_size>;
using pointer = index_data*;
using const_pointer = const index_data*;
indices_t(histogram_type* h) noexcept : hist_{h} {} indices_t(histogram_type* h) noexcept : hist_{h} {}
constexpr auto end() noexcept { return base_type::begin() + hist_->rank(); } using base_type::operator[];
constexpr auto end() const noexcept { return base_type::begin() + hist_->rank(); } unsigned size() const noexcept { return hist_->rank(); }
pointer begin() noexcept { return base_type::data(); }
const_pointer begin() const noexcept { return base_type::data(); }
pointer end() noexcept { return begin() + size(); }
const_pointer end() const noexcept { return begin() + size(); }
histogram_type* hist_; histogram_type* hist_;
} indices_; } indices_;
friend class indexed_range; friend class indexed_range;
}; };
indexed_range(histogram_type& hist, coverage cov) : begin_(&hist), end_(&hist) { indexed_range(histogram_type& hist, coverage cov)
std::size_t stride = 1; : begin_(hist.begin(), hist), end_(hist.end(), hist) {
auto ca = begin_.indices_.begin(); begin_.indices_.hist_->for_each_axis([ca = begin_.indices_.begin(), cov,
const auto clast = ca + begin_.indices_.hist_->rank() - 1; stride = std::size_t{1},
begin_.indices_.hist_->for_each_axis( this](const auto& a) mutable {
[ca, clast, cov, &stride, this](const auto& a) mutable { using opt = axis::traits::static_options<std::decay_t<decltype(a)>>;
using opt = axis::traits::static_options<std::decay_t<decltype(a)>>; constexpr axis::index_type under = opt::test(axis::option::underflow);
constexpr int under = opt::test(axis::option::underflow); constexpr axis::index_type over = opt::test(axis::option::overflow);
constexpr int over = opt::test(axis::option::overflow); const auto size = a.size();
const auto size = a.size();
ca->extent = size + under + over; // -1 if underflow and cover all, else 0
// -1 if underflow and cover all, else 0 ca->begin = cov == coverage::all ? -under : 0;
ca->begin = cov == coverage::all ? -under : 0; // size + 1 if overflow and cover all, else size
// size + 1 if overflow and cover all, else size ca->end = cov == coverage::all ? size + over : size;
ca->end = cov == coverage::all ? size + over : size; ca->idx = ca->begin;
ca->idx = ca->begin;
begin_.iter_ += (ca->begin + under) * stride; // if axis has *flow and coverage::all OR axis has no *flow:
end_.iter_ += ((ca < clast ? ca->begin : ca->end) + under) * stride; // begin + under == 0, size + over - end == 0
// if axis has *flow and coverage::inner:
// begin + under == 1, size + over - end == 1
ca->begin_skip = static_cast<std::size_t>(ca->begin + under) * stride;
ca->end_skip = static_cast<std::size_t>(size + over - ca->end) * stride;
begin_.iter_ += ca->begin_skip;
stride *= ca->extent; stride *= size + under + over;
++ca; ++ca;
}); });
} }
iterator begin() noexcept { return begin_; } iterator begin() noexcept { return begin_; }