https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101978
while preparing release of latest LogATE version, i stumbled upon a bug in thread sanitizer. consider the following piece of code:
#include <thread> #include <mutex> #include <condition_variable> int main() { auto ready = false; std::mutex m; std::condition_variable cv; std::thread th{ [&]{ // thread 1 std::unique_lock<std::mutex> lock(m); #if 0 // OK! cv.wait( lock, [&]{ return ready; } ); #endif #if 0 // ERROR! cv.wait_until( lock, std::chrono::steady_clock::now() + std::chrono::minutes{1}, [&]{ return ready; } ); #endif #if 1 // ERROR! cv.wait_for( lock, std::chrono::minutes{1}, [&]{ return ready; } ); #endif } }; { // thread 2 std::this_thread::sleep_for( std::chrono::seconds{1} ); // we should be wait()ing here std::lock_guard<std::mutex> lock{m}; ready = true; cv.notify_one(); } th.join(); }
after compiling it with:
g++ -fsanitize=thread -g3 -Wall -std=c++17 test.cpp -lpthread
we can see a very colorful output, indicating double-locking and race condition!
the same issue is reported with both gcc
and clang
. so the problem is in the code, right? well… no. the clue that the problem is elsewhere is when you change which version of wait()
is selected: regular one works fine, while time-constrained versions (i.e. deadline and timeout) report issues as below. changing C++ library does not change the output, but changing a compiler version does help.
here are the bugs i found already reported for this:
i've spent quite a bit of time today, trying to narrow down the issue and making it small and reproducible issue. then it turned out it's a know problem. life… ;)
the problem has been observed on UTs. even though here it was false-positive, running automated tests with sanitizers is a really great thing to do. if you still do not do it – i strongly encourage you to start doing so! :)