Open vdemichev opened 5 months ago
I have a fix, but not a fully one, because of that also no pull-request. First a test to verify the behaviour: add this to TestVector:
// Issue #524 check
{
struct S {
std::string s;
};
{
S s = {"Hello World!"};
eastl::vector<S> v;
v.pushBack(s);
v.pushBack(v.back());
VERIFY(v[0].s.compare("Hello World!") == 0);
VERIFY(v[1].s.compare("Hello World!") == 0);
VERIFY(v.size()==2);
}
}
the fix is (approx line 1946 in vector.h):
//here #524 is fixed!
::new((void*)(pNewData+(mpEnd-mpBegin))) value_type(eastl::forward<Args>(args)...); //first construct the new element in the destination buffer because the source might get moved away by the next line
pointer pNewEnd = eastl::uninitializedMove_ptr_if_noexcept(mpBegin, mpEnd, pNewData); //and here copy the rest of the elements into the new buffer
pNewEnd++;
BUT this will only fix the issue if you have exceptions disabled, when they're enabled it's NOT fixed (and I'm not confident enough to also fix the behaviour here).
Below steps to reproduce (MSVC 2022):
Expected output:
Actual output:
What happens: void vector<T, Allocator>::DoInsertValueEnd(Args&&... args) does this:
If realloc is needed, the vector contents are moved to the newly allocated chunk of memory. This invalidates the previously obtained reference to the object that is to be pushed back. Then a copy constructor is called using this invalid reference. All this happens silently, i.e. leads to difficult to track critical bugs in the program. I checked the commit history, the bug seems to have been there for years.
Btw, void vector<T, Allocator>::DoInsertValue(const_iterator position, Args&&... args) works correctly: