https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60966
--- Comment #14 from Hideaki Kimura <hideaki.kimura at gmail dot com> --- (In reply to Jonathan Wakely from comment #13) > This means you are waiting on an object that has gone out of scope. WIthout > more information it's not possible to tell if this is a bug in your program > or the standard libary. > > I'll try to reproduce it with Thomas's code... Hey Jonathan, I'm not sure if this helps, but could you try the following code snippet? #include <future> #include <iostream> #include <thread> #include <vector> struct DummyTask { DummyTask(int id) : id_(id) {} int id_; std::promise<void> pr; }; const int THREADS = 100; void run_task(DummyTask* task) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); task->pr.set_value(); } void wait_for_task(DummyTask* task) { task->pr.get_future().wait(); } int main() { std::vector<DummyTask*> tasks; std::vector<std::thread*> threads; for (int i = 0; i < THREADS; ++i) { DummyTask* task = new DummyTask(i); tasks.push_back(task); threads.push_back(new std::thread(run_task, task)); } for (int i = 0; i < THREADS; ++i) { wait_for_task(tasks[i]); // Because we returned from wait_for_task for this task, run_task is surely done. // No one else is referring to the task. So, even before threads[i]->join(), // it should be safe to delete it now. delete tasks[i]; // but here you get an invalid read! } for (int i = 0; i < THREADS; ++i) { threads[i]->join(); delete threads[i]; } return 0; } Run it a few times on valgrind. You will see what I got. If you move threads[i]->join() to the line before delete tasks[i], you don't get the issue. [Assuming that I'm not terribly missing something..] My bet is that std::promise puts something on thread-local, which causes some issue when std::promise's destructor is called before the corresponding thread's join() is called.