Fix past-the-end dereference in values_and_holders

The value and holder iterator code had a past-the-end iterator
dereference.  While of course invalid, the dereference didn't actually
cause any problems (which is why it wasn't caught before) because the
dereferenced value is never actually used and `vector` implementations
appear to allow dereferencing the past-the-end iterator.  Under a MSVC
debug build, however, it fails a debug assertion and aborts.

This amends the iterator to just store and use a pointer to the vector
(rather than adding a second past-the-end iterator member), checking the
type index against the type vector size.
This commit is contained in:
Jason Rhinelander 2017-07-12 10:18:09 -04:00
parent fd47779f40
commit a403d0e675

View File

@ -311,14 +311,13 @@ public:
struct iterator { struct iterator {
private: private:
instance *inst; instance *inst;
using vec_iter = std::vector<detail::type_info *>::const_iterator; const type_vec *types;
vec_iter typeit;
value_and_holder curr; value_and_holder curr;
friend struct values_and_holders; friend struct values_and_holders;
iterator(instance *inst, const type_vec &tinfo) iterator(instance *inst, const type_vec *tinfo)
: inst{inst}, typeit{tinfo.begin()}, : inst{inst}, types{tinfo},
curr(inst /* instance */, curr(inst /* instance */,
tinfo.size() > 0 ? *typeit : nullptr /* type info */, types->empty() ? nullptr : (*types)[0] /* type info */,
0, /* vpos: (non-simple types only): the first vptr comes first */ 0, /* vpos: (non-simple types only): the first vptr comes first */
0 /* index */) 0 /* index */)
{} {}
@ -328,18 +327,17 @@ public:
bool operator==(const iterator &other) { return curr.index == other.curr.index; } bool operator==(const iterator &other) { return curr.index == other.curr.index; }
bool operator!=(const iterator &other) { return curr.index != other.curr.index; } bool operator!=(const iterator &other) { return curr.index != other.curr.index; }
iterator &operator++() { iterator &operator++() {
if (!inst->simple_layout) { if (!inst->simple_layout)
curr.vh += 1 + (*typeit)->holder_size_in_ptrs; curr.vh += 1 + (*types)[curr.index]->holder_size_in_ptrs;
curr.type = *(++typeit);
}
++curr.index; ++curr.index;
curr.type = curr.index < types->size() ? (*types)[curr.index] : nullptr;
return *this; return *this;
} }
value_and_holder &operator*() { return curr; } value_and_holder &operator*() { return curr; }
value_and_holder *operator->() { return &curr; } value_and_holder *operator->() { return &curr; }
}; };
iterator begin() { return iterator(inst, tinfo); } iterator begin() { return iterator(inst, &tinfo); }
iterator end() { return iterator(tinfo.size()); } iterator end() { return iterator(tinfo.size()); }
iterator find(const type_info *find_type) { iterator find(const type_info *find_type) {