https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92731

            Bug ID: 92731
           Summary: Data race on exception object thrown from std::future
           Product: gcc
           Version: 8.3.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: rrrlasse at hotmail dot com
  Target Milestone: ---

Created attachment 47397
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=47397&action=edit
TSan output and .ii file

The source is compiled with: 
g++ cpp.cpp -lpthread -fsanitize=thread -Wall -Wextra

After running for around 100 - 500 iteration in the for-loop of the main
thread, TSan reports a data race between the destructor of the exception object
and the strlen() loop.

If you omit the std::move(packaged_task) the warning disappears.

uname -a: Linux ubuntu 5.0.0-29-generic #31-Ubuntu SMP Thu Sep 12 13:05:32 UTC
2019 x86_64 x86_64 x86_64 GNU/Linux

g++ --version: g++ (Ubuntu 8.3.0-6ubuntu1) 8.3.0

Since you can apparently only add a single attachment, I've colledted the .ii
file and tsan report in a zip file.

Source code:

#include <iostream>
#include <optional>
#include <stdexcept>
#include <mutex>
#include <future>
#include <cstring>

std::condition_variable cv;
std::mutex mu;
std::function<void()> job;
bool has_job = false;

void looper() {
    for (;;) {
        std::unique_lock <std::mutex> ul(mu);
        while (!has_job) {
            cv.wait(ul);
        }
        has_job = false;
        job();
    }
}

//  g++ cpp.cpp -lpthread -fsanitize=thread -Wall -Wextra

int main() {
    std::thread t = std::thread(looper);
    for (int c = 0; ; c++) {
        try {
            std::packaged_task<void()> packaged_task([]() { throw
std::runtime_error("aaaaaaaaaaaaaaaaa"); });
            std::future<void>          task_future =
packaged_task.get_future();
            {
                std::unique_lock<std::mutex> ul(mu);
                job = [&]() {
#if 1
                    // tsan warning
                    std::packaged_task<void ()> tmp(std::move(packaged_task));
                    tmp();
#else
                    // no warning
                    packaged_task();
#endif
                };
                has_job = true;
                cv.notify_one();
            }
            task_future.get();
        }
        catch (const std::runtime_error& e) {
            for (int i = 0; i < 10; i++) {
                [[maybe_unused]] int a = strlen(e.what());
            }
        }
    }
}

Reply via email to