CheckQueue_Correct_Random data race #22548

issue Crypt-iQ opened this issue on July 25, 2021
  1. Crypt-iQ commented at 7:12 PM on July 25, 2021: contributor

    Compiler: clang 12.0.0

    OS: Arch Linux

    Optimization flags: occurs under -O0, -O1, or -Os but not the default of -O2

    Sanitizer: thread

    Bitcoin commit: 1488f55

    Configure command: CC=clang CXX=clang++ CFLAGS="-O0" CXXFLAGS="-O0" ./configure --disable-wallet --with-sanitizers=thread

    <details closed> <summary>TSAN output</summary> <br>

    WARNING: ThreadSanitizer: data race (pid=1655626)
      Read of size 4 at 0x7b6000000e38 by thread T4 (mutexes: write M131995):
        [#0](/bitcoin-bitcoin/0/) CConnman::GetExtraBlockRelayCount() const <null> (test_bitcoin+0xd338c6)
        [#1](/bitcoin-bitcoin/1/) (anonymous namespace)::PeerManagerImpl::EvictExtraOutboundPeers(long) <null> (test_bitcoin+0xde5ec7)
        [#2](/bitcoin-bitcoin/2/) (anonymous namespace)::PeerManagerImpl::CheckForStaleTipAndEvictPeers() <null> (test_bitcoin+0xdb7cac)
        [#3](/bitcoin-bitcoin/3/) (anonymous namespace)::PeerManagerImpl::PeerManagerImpl(CChainParams const&, CConnman&, CAddrMan&, BanMan*, CScheduler&, ChainstateManager&, CTxMemPool&, bool)::$_2::operator()() const <null> (test_bitcoin+0xddb062)
        [#4](/bitcoin-bitcoin/4/) void std::__invoke_impl<void, (anonymous namespace)::PeerManagerImpl::PeerManagerImpl(CChainParams const&, CConnman&, CAddrMan&, BanMan*, CScheduler&, ChainstateManager&, CTxMemPool&, bool)::$_2&>(std::__invoke_other, (anonymous namespace)::PeerManagerImpl::PeerManagerImpl(CChainParams const&, CConnman&, CAddrMan&, BanMan*, CScheduler&, ChainstateManager&, CTxMemPool&, bool)::$_2&) <null> (test_bitcoin+0xddaf8a)
        [#5](/bitcoin-bitcoin/5/) std::enable_if<is_invocable_r_v<void, (anonymous namespace)::PeerManagerImpl::PeerManagerImpl(CChainParams const&, CConnman&, CAddrMan&, BanMan*, CScheduler&, ChainstateManager&, CTxMemPool&, bool)::$_2&>, void>::type std::__invoke_r<void, (anonymous namespace)::PeerManagerImpl::PeerManagerImpl(CChainParams const&, CConnman&, CAddrMan&, BanMan*, CScheduler&, ChainstateManager&, CTxMemPool&, bool)::$_2&>((anonymous namespace)::PeerManagerImpl::PeerManagerImpl(CChainParams const&, CConnman&, CAddrMan&, BanMan*, CScheduler&, ChainstateManager&, CTxMemPool&, bool)::$_2&) <null> (test_bitcoin+0xddae6a)
        [#6](/bitcoin-bitcoin/6/) std::_Function_handler<void (), (anonymous namespace)::PeerManagerImpl::PeerManagerImpl(CChainParams const&, CConnman&, CAddrMan&, BanMan*, CScheduler&, ChainstateManager&, CTxMemPool&, bool)::$_2>::_M_invoke(std::_Any_data const&) <null> (test_bitcoin+0xddac2b)
        [#7](/bitcoin-bitcoin/7/) std::function<void ()>::operator()() const <null> (test_bitcoin+0x9492c8)
        [#8](/bitcoin-bitcoin/8/) Repeat(CScheduler&, std::function<void ()>, std::chrono::duration<long, std::ratio<1l, 1000l> >) <null> (test_bitcoin+0x141431a)
        [#9](/bitcoin-bitcoin/9/) CScheduler::scheduleEvery(std::function<void ()>, std::chrono::duration<long, std::ratio<1l, 1000l> >)::$_0::operator()() const <null> (test_bitcoin+0x141422d)
        [#10](/bitcoin-bitcoin/10/) void std::__invoke_impl<void, CScheduler::scheduleEvery(std::function<void ()>, std::chrono::duration<long, std::ratio<1l, 1000l> >)::$_0&>(std::__invoke_other, CScheduler::scheduleEvery(std::function<void ()>, std::chrono::duration<long, std::ratio<1l, 1000l> >)::$_0&) <null> (test_bitcoin+0x141411a)
        [#11](/bitcoin-bitcoin/11/) std::enable_if<is_invocable_r_v<void, CScheduler::scheduleEvery(std::function<void ()>, std::chrono::duration<long, std::ratio<1l, 1000l> >)::$_0&>, void>::type std::__invoke_r<void, CScheduler::scheduleEvery(std::function<void ()>, std::chrono::duration<long, std::ratio<1l, 1000l> >)::$_0&>(CScheduler::scheduleEvery(std::function<void ()>, std::chrono::duration<long, std::ratio<1l, 1000l> >)::$_0&) <null> (test_bitcoin+0x141401a)
        [#12](/bitcoin-bitcoin/12/) std::_Function_handler<void (), CScheduler::scheduleEvery(std::function<void ()>, std::chrono::duration<long, std::ratio<1l, 1000l> >)::$_0>::_M_invoke(std::_Any_data const&) <null> (test_bitcoin+0x1413c6b)
        [#13](/bitcoin-bitcoin/13/) std::function<void ()>::operator()() const <null> (test_bitcoin+0x9492c8)
        [#14](/bitcoin-bitcoin/14/) CScheduler::serviceQueue() <null> (test_bitcoin+0x1412362)
        [#15](/bitcoin-bitcoin/15/) ChainTestingSetup::ChainTestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&)::$_0::operator()() const <null> (test_bitcoin+0xbb5b6e)
        [#16](/bitcoin-bitcoin/16/) void std::__invoke_impl<void, ChainTestingSetup::ChainTestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&)::$_0&>(std::__invoke_other, ChainTestingSetup::ChainTestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&)::$_0&) <null> (test_bitcoin+0xbb5a8a)
        [#17](/bitcoin-bitcoin/17/) std::enable_if<is_invocable_r_v<void, ChainTestingSetup::ChainTestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&)::$_0&>, void>::type std::__invoke_r<void, ChainTestingSetup::ChainTestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&)::$_0&>(ChainTestingSetup::ChainTestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&)::$_0&) <null> (test_bitcoin+0xbb596a)
        [#18](/bitcoin-bitcoin/18/) std::_Function_handler<void (), ChainTestingSetup::ChainTestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&)::$_0>::_M_invoke(std::_Any_data const&) <null> (test_bitcoin+0xbb572b)
        [#19](/bitcoin-bitcoin/19/) std::function<void ()>::operator()() const <null> (test_bitcoin+0x9492c8)
        [#20](/bitcoin-bitcoin/20/) util::TraceThread(char const*, std::function<void ()>) <null> (test_bitcoin+0x1546098)
        [#21](/bitcoin-bitcoin/21/) void std::__invoke_impl<void, void (*)(char const*, std::function<void ()>), char const*, ChainTestingSetup::ChainTestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&)::$_0>(std::__invoke_other, void (*&&)(char const*, std::function<void ()>), char const*&&, ChainTestingSetup::ChainTestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&)::$_0&&) <null> (test_bitcoin+0xbb53e0)
        [#22](/bitcoin-bitcoin/22/) std::__invoke_result<void (*)(char const*, std::function<void ()>), char const*, ChainTestingSetup::ChainTestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&)::$_0>::type std::__invoke<void (*)(char const*, std::function<void ()>), char const*, ChainTestingSetup::ChainTestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&)::$_0>(void (*&&)(char const*, std::function<void ()>), char const*&&, ChainTestingSetup::ChainTestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&)::$_0&&) <null> (test_bitcoin+0xbb5124)
        [#23](/bitcoin-bitcoin/23/) void std::thread::_Invoker<std::tuple<void (*)(char const*, std::function<void ()>), char const*, ChainTestingSetup::ChainTestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&)::$_0> >::_M_invoke<0ul, 1ul, 2ul>(std::_Index_tuple<0ul, 1ul, 2ul>) <null> (test_bitcoin+0xbb5068)
        [#24](/bitcoin-bitcoin/24/) std::thread::_Invoker<std::tuple<void (*)(char const*, std::function<void ()>), char const*, ChainTestingSetup::ChainTestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&)::$_0> >::operator()() <null> (test_bitcoin+0xbb4fa2)
        [#25](/bitcoin-bitcoin/25/) std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(char const*, std::function<void ()>), char const*, ChainTestingSetup::ChainTestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&)::$_0> > >::_M_run() <null> (test_bitcoin+0xbb4c4a)
        [#26](/bitcoin-bitcoin/26/) execute_native_thread_routine /build/gcc/src/gcc/libstdc++-v3/src/c++11/thread.cc:82:18 (libstdc++.so.6+0xd33c3)
    
      Previous write of size 4 at 0x7b6000000e38 by main thread:
        [failed to restore the stack]
    
      Location is heap block of size 952 at 0x7b6000000c00 allocated by main thread:
        [#0](/bitcoin-bitcoin/0/) operator new(unsigned long) <null> (test_bitcoin+0x18da0e)
        [#1](/bitcoin-bitcoin/1/) std::_MakeUniq<CConnman>::__single_object std::make_unique<CConnman, int, int, CAddrMan&>(int&&, int&&, CAddrMan&) <null> (test_bitcoin+0x460d55)
        [#2](/bitcoin-bitcoin/2/) TestingSetup::TestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&) <null> (test_bitcoin+0xbb2234)
        [#3](/bitcoin-bitcoin/3/) checkqueue_tests::test_CheckQueue_Correct_Random::test_CheckQueue_Correct_Random() <null> (test_bitcoin+0x3a0456)
        [#4](/bitcoin-bitcoin/4/) checkqueue_tests::test_CheckQueue_Correct_Random_invoker() <null> (test_bitcoin+0x386593)
        [#5](/bitcoin-bitcoin/5/) boost::detail::function::void_function_invoker0<void (*)(), void>::invoke(boost::detail::function::function_buffer&) <null> (test_bitcoin+0x21af3b)
        [#6](/bitcoin-bitcoin/6/) <null> <null> (libboost_unit_test_framework.so.1.76.0+0x3266d)
        [#7](/bitcoin-bitcoin/7/) __libc_start_main <null> (libc.so.6+0x27b24)
    
      Mutex M131995 (0x564a0fd62388) created at:
        [#0](/bitcoin-bitcoin/0/) pthread_mutex_lock <null> (test_bitcoin+0x130f28)
        [#1](/bitcoin-bitcoin/1/) __gthread_mutex_lock(pthread_mutex_t*) <null> (test_bitcoin+0x1db5f0)
        [#2](/bitcoin-bitcoin/2/) __gthread_recursive_mutex_lock(pthread_mutex_t*) <null> (test_bitcoin+0x1db922)
        [#3](/bitcoin-bitcoin/3/) std::recursive_mutex::lock() <null> (test_bitcoin+0x1e0c26)
        [#4](/bitcoin-bitcoin/4/) std::unique_lock<std::recursive_mutex>::lock() <null> (test_bitcoin+0x1e0b86)
        [#5](/bitcoin-bitcoin/5/) UniqueLock<AnnotatedMixin<std::recursive_mutex>, std::unique_lock<std::recursive_mutex> >::Enter(char const*, char const*, int) <null> (test_bitcoin+0x1e0680)
        [#6](/bitcoin-bitcoin/6/) UniqueLock<AnnotatedMixin<std::recursive_mutex>, std::unique_lock<std::recursive_mutex> >::UniqueLock(AnnotatedMixin<std::recursive_mutex>&, char const*, char const*, int, bool) <null> (test_bitcoin+0x1e0369)
        [#7](/bitcoin-bitcoin/7/) ChainstateManager::ActiveChainstate() const <null> (test_bitcoin+0x127d67c)
        [#8](/bitcoin-bitcoin/8/) TestingSetup::TestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&) <null> (test_bitcoin+0xbb1bc9)
        [#9](/bitcoin-bitcoin/9/) checkqueue_tests::test_CheckQueue_Correct_Zero::test_CheckQueue_Correct_Zero() <null> (test_bitcoin+0x3955e6)
        [#10](/bitcoin-bitcoin/10/) checkqueue_tests::test_CheckQueue_Correct_Zero_invoker() <null> (test_bitcoin+0x3841cb)
        [#11](/bitcoin-bitcoin/11/) boost::detail::function::void_function_invoker0<void (*)(), void>::invoke(boost::detail::function::function_buffer&) <null> (test_bitcoin+0x21af3b)
        [#12](/bitcoin-bitcoin/12/) <null> <null> (libboost_unit_test_framework.so.1.76.0+0x3266d)
        [#13](/bitcoin-bitcoin/13/) __libc_start_main <null> (libc.so.6+0x27b24)
    
      Thread T4 'b-scheduler' (tid=1655646, running) created by main thread at:
        [#0](/bitcoin-bitcoin/0/) pthread_create <null> (test_bitcoin+0x14574e)
        [#1](/bitcoin-bitcoin/1/) __gthread_create /build/gcc/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/gthr-default.h:663:35 (libstdc++.so.6+0xd36aa)
        [#2](/bitcoin-bitcoin/2/) std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) /build/gcc/src/gcc/libstdc++-v3/src/c++11/thread.cc:147:37 (libstdc++.so.6+0xd36aa)
        [#3](/bitcoin-bitcoin/3/) ChainTestingSetup::ChainTestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&) <null> (test_bitcoin+0xbb1423)
        [#4](/bitcoin-bitcoin/4/) TestingSetup::TestingSetup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<char const*, std::allocator<char const*> > const&) <null> (test_bitcoin+0xbb1b14)
        [#5](/bitcoin-bitcoin/5/) checkqueue_tests::test_CheckQueue_Correct_Random::test_CheckQueue_Correct_Random() <null> (test_bitcoin+0x3a0456)
        [#6](/bitcoin-bitcoin/6/) checkqueue_tests::test_CheckQueue_Correct_Random_invoker() <null> (test_bitcoin+0x386593)
        [#7](/bitcoin-bitcoin/7/) boost::detail::function::void_function_invoker0<void (*)(), void>::invoke(boost::detail::function::function_buffer&) <null> (test_bitcoin+0x21af3b)
        [#8](/bitcoin-bitcoin/8/) <null> <null> (libboost_unit_test_framework.so.1.76.0+0x3266d)
        [#9](/bitcoin-bitcoin/9/) __libc_start_main <null> (libc.so.6+0x27b24)
    
    SUMMARY: ThreadSanitizer: data race (/root/bitcoin/src/test/test_bitcoin+0xd338c6) in CConnman::GetExtraBlockRelayCount() const
    

    </details>

    TSAN warns on the following functions for data race:

    • GetExtraBlockRelayCount
    • GetExtraFullOutboundCount
    • GetUseAddrmanOutgoing

    I believe this is because a call to PeerManager::make will schedule CheckForStaleTipAndEvictPeers (with a delay of 45 seconds) which reads the variables and the call to CConnman::Init will write the variables specified in the passed connOptions reference. There is no locking. TSAN only warns on this specific test. It seems to me that this race could also happen during normal bitcoind operation (if startup was very slow), but maybe I'm mistaken.

  2. Crypt-iQ commented at 3:50 PM on August 4, 2021: contributor

    Closed with 5b2d8661c906ea1bc7afd904aad9b04a691d86cd

  3. Crypt-iQ closed this on Aug 4, 2021

  4. DrahtBot locked this on Aug 18, 2022

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-13 21:14 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me