libstdc++ bug with push_back to duplicate vecor element

Viewed 49

I've got the following bug with the small program below:

#include <vector>
#include <iostream>

using namespace std;

int main() {
    vector<int> t;
    t.push_back(0);
    for(int i = 1; i < 1024; i++) {
        auto& x = t[i-1];
        t.push_back(x);
        t.push_back(x);
        t.push_back(x);
    }
    return 0;
}

It compiles fine and execute without any error. But if you run it (Linux machine) with valgrind, you get a memory error:

==122572== Invalid read of size 4
==122572==    at 0x10A051: void __gnu_cxx::new_allocator<int>::construct<int, int const&>(int*, int const&) (in /home/casse/tmp/bug)
...

Now, if you change the code above a bit:

auto x = t[i-1];

(instead of taking the reference, you copy the element from the vector), valgrind doesn't complain anymore.

Any idea?

1 Answers

push_back might cause reallocation then all the references are invalidated, and dereference on invalidated reference leads to UB.

If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated.

You can use reserve in advance to avoid reallocation.

vector<int> t;
t.reserve(1 + 1023 * 3);
t.push_back(0);
for(int i = 1; i < 1024; i++) {
    auto& x = t[i-1];
    t.push_back(x);
    t.push_back(x);
    t.push_back(x);
}

On the other hand, for auto x = t[i-1];, x is copied from t[i-1] and independent of t[i-1], no invalidated reference issue again.

Related