0

I am encountering a problem that Valgrind/Helgrind does not recognize std::future as mentioned in this answer. In that answer, the solution is to use clang and libc++ instead of gcc/libstdc++.

I use Ubuntu 18.04 and use apt to install clang 6.0.0, but when I run

clang++ helgrind_test.cc -lpthread -std=c++11 -stdlib=libc++ -o helgrind_test

I got the following error:

helgrind_test.cc:1:10: fatal error: 'future' file not found
#include <future>
         ^~~~~~~~
1 error generated.  

Using libstdc++ will get the code compiles but it does not remove helgrind error.

Can you help me figure out what's going wrong?

The helgrind_test.cc source code is here:

#include <future>
#include <iostream>
#include <mutex>

#define _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(A) ANNOTATE_HAPPENS_BEFORE(A)
#define _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(A)  ANNOTATE_HAPPENS_AFTER(A)

using namespace std;

promise<int> promise_;

void run() {
    int result = 0;
    for(int i = 0 ; i < 100000;++i) {
            result += i;
    }
    promise_.set_value(result);
}

int main() {
    auto f = promise_.get_future();
    thread another(run);
    another.detach();

    cout << f.get() << endl;
}

And the error I got from helgrind is like:

==73696== Possible data race during read of size 4 at 0x5DA2D00 by thread #1
==73696== Locks held: none
==73696==    at 0x40215B: std::future<int>::get() (in /home/cc/helgrind_test)
==73696==    by 0x401BF3: main (in /home/cc/helgrind_test)
==73696==
==73696== This conflicts with a previous write of size 4 by thread #2
==73696== Locks held: none
==73696==    at 0x40529A: std::__future_base::_Result<int>::_M_set(int const&) (in /home/cc/helgrind_test)
==73696==    by 0x4051CD: std::__future_base::_State_baseV2::_Setter<int, int const&>::operator()() const (in /home/cc/helgrind_test)
==73696==    by 0x404FCE: std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_State_baseV2::_Setter<int, int const&> >::_M_invoke(std::_Any_data const&) (in /home/cc/helgrind_test)
==73696==    by 0x404E9C: std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const (in /home/cc/helgrind_test)
==73696==    by 0x404BBB: std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) (in /home/cc/helgrind_test)
==73696==    by 0x404E40: void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) (in /home/cc/helgrind_test)
==73696==    by 0x404D4B: std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) (in /home/cc/helgrind_test)
==73696==    by 0x404CE5: void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const (in /home/cc/helgrind_test)
==73696==  Address 0x5da2d00 is 16 bytes inside a block of size 24 alloc'd
==73696==    at 0x4C3159F: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==73696==    by 0x401E63: std::promise<int>::promise() (in /home/cc/helgrind_test)
==73696==    by 0x401A16: __cxx_global_var_init.1 (in /home/cc/helgrind_test)
==73696==    by 0x401A5D: _GLOBAL__sub_I_helgrind_test.cc (in /home/cc/helgrind_test)
==73696==    by 0x40691C: __libc_csu_init (in /home/cc/helgrind_test)
==73696==    by 0x59C1B27: (below main) (libc-start.c:266)
==73696==  Block was alloc'd by thread #1
Harper
  • 1,794
  • 14
  • 31
  • Did you also install `libc++-dev`? – rustyx May 26 '20 at 19:05
  • @eerorika that's a documented interface of libstdc++ (https://gcc.gnu.org/onlinedocs/libstdc++/manual/debug.html) – Marc Glisse May 26 '20 at 19:09
  • @rustyx Thanks! After installing libc++-dev and libc++-abi-dev I am able to run clang and get rid of the false positive from helgrind. Now I need to start switching my entire project from GCC to clang... – Harper May 26 '20 at 19:13
  • @MarcGlisse That's also an interesting point. The GCC documents said these macros will help data race hunting with Helgrind, which means they have the idea in mind. But after so many years, helgrind still cannot work well with gcc future, which is part of c++11. – Harper May 26 '20 at 19:16
  • @MarcGlisse Ah, thanks for pointing out. – eerorika May 26 '20 at 19:17
  • Clang 6 is pretty old and not necessarily better/faster than GCC. Also see the dupe... on Ubuntu, libc++-dev is fairly old too, so might be worth building a newer version from source. – rustyx May 26 '20 at 19:28

0 Answers0