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.
diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h
index c7b8edc..27d5622 100644
--- a/include/pybind11/cast.h
+++ b/include/pybind11/cast.h
@@ -311,14 +311,13 @@
struct iterator {
private:
instance *inst;
- using vec_iter = std::vector<detail::type_info *>::const_iterator;
- vec_iter typeit;
+ const type_vec *types;
value_and_holder curr;
friend struct values_and_holders;
- iterator(instance *inst, const type_vec &tinfo)
- : inst{inst}, typeit{tinfo.begin()},
+ iterator(instance *inst, const type_vec *tinfo)
+ : inst{inst}, types{tinfo},
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 /* index */)
{}
@@ -328,18 +327,17 @@
bool operator==(const iterator &other) { return curr.index == other.curr.index; }
bool operator!=(const iterator &other) { return curr.index != other.curr.index; }
iterator &operator++() {
- if (!inst->simple_layout) {
- curr.vh += 1 + (*typeit)->holder_size_in_ptrs;
- curr.type = *(++typeit);
- }
+ if (!inst->simple_layout)
+ curr.vh += 1 + (*types)[curr.index]->holder_size_in_ptrs;
++curr.index;
+ curr.type = curr.index < types->size() ? (*types)[curr.index] : nullptr;
return *this;
}
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 find(const type_info *find_type) {