0

I have a global vector of vector of structs of this form:

vector<vector<stackEntry>> shadowStacksVector

where the idea is to have a vector<stackEntry> per thread.

In the thread start function I do the following:

vector<stackEntry> sstack;
shadowStacksVector.push_back(sstack);
tdata->shadowStack = &(shadowStacksVector.back());

where tdata is a struct containing the thread local storage. What I would like to do is to have, for each thread, a reference to the vector of stack entries, so that each thread can add or remove elements to its own stack. Conceptually I believe that push_back does a copy of the element so I thought that this should have worked. However, when I try to add/remove elements from tdata->shadowStack my program crashes.

On the contary, if I replace the vector of vectors with an array like this:

vector<stackEntry> shadowStacksVector[256]

everything works fine.

Simus
  • 319
  • 2
  • 18
  • Possible dupe: https://stackoverflow.com/questions/34708189/c-vector-of-pointer-loses-the-reference-after-push-back – Rakete1111 Apr 28 '18 at 08:03
  • If you want one vector per thread, it can be a thread-local vector. Is there a component that needs to access other threads' vectors? – chris Apr 28 '18 at 08:03
  • 3
    As soon as that outer vector resizes due to expansion when you're starting all those hosts, all the previous pointers are useless, left dangling in the ether. `reserve` the initial size, and don't modify it again. Better still, send the initial vectors in by value and use move semantics to retain them local to each thread. IOW, get rid of `shadowStacksVector`. If you need it for *results*, have each thread safely push them in under the protection of a mutex right before the threads finish. – WhozCraig Apr 28 '18 at 08:05
  • 1
    Alternatively you can take list of vectors – PapaDiHatti Apr 28 '18 at 08:07
  • @Kapil Using a list of vectors worked! Why is that? – Simus Apr 28 '18 at 08:21

1 Answers1

2

Containers are not thread safe, you need to create thread-safe sections of code to work with them in several threads. Use std::mutex or std::atomic to create thread-safe sections of code.

Neither std::vector nor std::list is thread-safe. Your std::vector fails probably because when you push_back new value its allocated memory can do reallocate and all elements can move in other part of memory, so your old pointers can point on old broken data. If you will use shadowStacksVector->reserve(MAX_INTERNAL_VECTORS_COUNT) at start vector's memory won't be reallocating when you do push_back, it guarantees that std::vector reserved memory for MAX_INTERNAL_VECTORS_COUNT and next reallocate can happen after you will push_back MAX_INTERNAL_VECTORS_COUNT+1 element.

std::list don't need to reallocate all his elements, because its elements can store in different parts of memory, it allocates memory for each element every time you do push_back, so old pointers are point on the same place of memory.

Alexey Usachov
  • 1,364
  • 2
  • 8
  • 15