Put this code into MS Visual C++ 2010, compile (debug or release), and it will crash for the insert() loop, but not the push_back loop:
#include <vector>
#include <string>
using std::vector;
using std::string;
int main()
{
vector<string> vec1;
vec1.push_back("hello");
for (int i = 0; i != 10; ++i)
vec1.push_back( vec1[0] );
vector<string> vec2;
vec2.push_back("hello");
for (int i = 0; i != 10; ++i)
vec2.insert( vec2.end(), vec2[0] );
return 0;
}
The problem is that both push_back() and insert() take the new item by reference, and when the vector is realloced for more space, the new item becomes invalidated BEFORE it is inserted.
GCC should also have this problem. I have not checked Clang, but it depends which STD library it is using.
MSVC2010 has some extra code in push_back() that detects if the new item is actually an item within the vector. If so, it records the item's index and uses that to insert the item after memory has been alloced (instead of using the now-invalidated reference) -- uses _Inside(_STD addressof(_Val))
Is MSVC's extra code non-standard?
My concern is that I am not sure in what code I may have done something like vec.push_back(vec[1]); or vec.insert(it, vec[2]); I'd have to look through hundreds if not thousands of lines of code that use push_back and insert, and that is just my own code... 3rd party libraries could also be affected.
I assume that GCC could be made to die in horrible ways using this technique (I see no extra code to handle this case, but valgrind didn't detect it in my simple example so will be harder to test),
How best to detect and avoid making this mistake?
Is MSVC2010's extra push_back() code non-standard? Should MSVC instead detect and assert when it finds vectors used in this way? (ie the secure-computing initiative)
I am thinking of hacking MSVC2010 and GCC's headers to detect these cases.
any other ideas?
Thanks, Paul
PS: note also that this usage is perfectly fine (and efficient) IF you can guarantee that the vector does not need to be resized