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

            Bug ID: 78158
           Summary: Strange data race detection with thread sanitizer
           Product: gcc
           Version: 6.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: sanitizer
          Assignee: unassigned at gcc dot gnu.org
          Reporter: morandidodo at gmail dot com
                CC: dodji at gcc dot gnu.org, dvyukov at gcc dot gnu.org,
                    jakub at gcc dot gnu.org, kcc at gcc dot gnu.org
  Target Milestone: ---

I am having an issue with the following piece of code:

#include <atomic>
#include <thread>
#include <cassert>
#include <iostream>
#include <chrono>
#include <cmath>
#include <vector>
#include <mutex>

using namespace std::chrono_literals;

static std::atomic_bool writing_locked = {false};
static std::atomic_int readers = {0};
static std::mutex mutex;
static std::atomic_bool loading = {false};

long double tester = 345.7654;

void fun()
{
    static constexpr unsigned iterations = 10000000;
    long double local_tester = 0.;

    for(unsigned iteration = 0;;)
    {
        if(not writing_locked)
        {
            int local_readers = readers;
            if(local_readers < 0)
            {
                std::lock_guard<std::mutex> lock(mutex);
                continue;
            }

            if(not readers.compare_exchange_weak(local_readers, local_readers +
1))
                continue;
        }
        else
        {
            std::lock_guard<std::mutex> lock(mutex);
            continue;
        }

        assert(readers > 0);

        for(unsigned i = 0; i < 1000; ++i)
            local_tester += std::log(tester); /* This line is said to race...
*/

        assert(readers > 0);
        --readers;

        if(static_cast<unsigned>(local_tester) % 500 == 0)
        {
            bool current_loading = false;
            if(loading.compare_exchange_strong(current_loading, true))
            {
                std::lock_guard<std::mutex> lock(mutex);
                writing_locked = true;

                int zero_readers = 0;
                do
                {
                    zero_readers = 0;
                } while(not readers.compare_exchange_weak(zero_readers, -1));

                assert(readers == -1);

                for(unsigned i = 0; i < 100; ++i)
                    tester = std::sqrt(std::pow(tester, 2) + 1); /* ...with
this line */

                assert(readers == -1);

                readers = 0;
                writing_locked = false;

                loading = false;
            }
        } else if(iteration++ >= iterations)
            return;
    }
}

int main()
{
    static const unsigned max_threads = std::thread::hardware_concurrency();
    std::vector<std::thread> threads(max_threads);
    for(unsigned i = 0; i < max_threads; ++i)
        threads[i] = std::thread(fun);

    for(unsigned i = 0; i < max_threads; ++i)
        threads[i].join();
}

IMHO there should not be any race in this code, but if it is compiled with
-fsanitize=thread, a data race is found between the two lines commented, but
only when NDEBUG is defined. clang does not warn about any issue.
I thought that it could be related to bug 68260, but I just compiled the last
version from Git and the problem is still there.

Reply via email to