C++ for-each statement triggers "vector iterators incompatible" assertion failure: this->_Getcont() == 0

c++, c++11, stl, vector

Solution

I finally found the problem. A path deep in the vector's setup code was clobbering the vector's state (memset'ing it to 0's as part of a larger chunk of memory). This caused no harm for the first three fields in vector: `_Myfirst`, `_Mylast`, and `_Myend` since those fields are 0 in an initial vector. Moreover, most things such as the array index operator and other methods such as push_back still functioned correctly. However, the fourth field `_Myproxy` was initially non-zero, and clearing it disabled iterator-based functionality. Hence, for-each loop, `vector::back()`, and others all fail with different false errors such as false bounds checks, false incompatible iterators, etc...

Problem

This is with Visual Studio 2012. ``` static void func( ..., const std::vector<std::string> &opt_extra_args_strs, ...) { // THIS ASSERTS: "vector iterators incompatible" for (const std::string &arg_str : opt_extra_args_strs) { ... body does not modify opt_extra_args_strs // BUT THIS WORKS: for (size_t a_ix = 0; a_ix < opt_extra_args_strs.size(); a_ix++) { const std::string &arg_str = opt_extra_args_strs[a_ix]; } ``` I am not modifying the vector at all in the loop body, and in fact, the assertion happens before the first iteration. The vector looks right in the debugger, but I don't know enough about STL to look for corruption. Inside the STL the assertion failure comes from: ``` void _Compat(const _Myiter& _Right) const { // test for compatible iterator pair if (this->_Getcont() == 0 // THIS FAILS (_Getcont() == 0) ...) { _DEBUG_ERROR("vector iterators incompatible"); ``` with `this->_Getcont()` being NULL because (`_Myproxy` is NULL in the `_Iterator_base12`). The call stack is: ``` msvcp110d.dll!std::_Debug_message(const wchar_t * message, const wchar_t * file, unsigned int line) Line 15 C++ Main.exe!std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > >::_Compat(const std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > > & _Right) Main.exe!std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > >::operator==(const std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > > & _Right) Main.exe!std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > >::operator!=(const std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > > & _Right) Main.exe!run_test(..., const std::vector<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > & opt_extra_args_strs) ... ``` I suspect the code setting up the vector is screwing it up somehow, but I am not sure. I am having difficulty writing a simpler reproducer as well, but the program should be totally deterministic (single threaded, not random variables, always asserts). Additionally, I also run into a different similar assertion failure earlier `"vector iterator + offset out of range"` with the snippet (on the same vector) ``` template <typename T> class Elsewhere { virtual void earlier( .... std::vector<T> &v) const { v.emplace_back(); // empty construction of a T // T &t = v.back(); // assertion failure T &val = to[to.size() - 1]; // but this works ... mutates val. ``` With `T = std::string` (in fact, the same vector). I mention this because within STL the condition for this failure ends up also being `this->_Getcont() == 0`, and I suspect them to be related. What does it mean for `_Getcont()` to be 0 in a `Vector_const_iterator`? The vector comes out of a container ``` template <typename T> struct type { T m_value; operator const T &() const { return value(); } const T &value() const { return m_value; } }; type<std::vector<std::string>> &t = ... method call that returns ref to it; ... t gets set func(t); // implicit conversion to (const std::vector<std::string> &) ```

Original source