Skip to content

Conversation

ryanofsky
Copy link
Collaborator

This PR fixes threadsanitizer errors that were found in bitcoin CI and reported by maflcko in bitcoin/bitcoin#33518 (comment). It also extends the libmultiprocess sanitize CI job to report the same errors.

Before this PR, libmultiprocess was built with threadsanitzer in CI, but cap'n proto and libc++ dependencies were built without it, so races in these libraries could be undetected.

Building libc++ with threadsanitzer triggered threadsanitzer errors about accessing std::cout from multiple threads. Those errors are suppressed in bitcoin CI, but there is not really a reason to suppress there here, so they are just fixed by replacing std::cout with KJ_LOG in the test. This change also cleans up mptest output, which is nice. Full output can be seen by running mptest --verbose.

Building cap'nproto with threadsanitzer triggered threadsanitzer errors in the new "thread busy" test added in #214. These were just caused by accessing some test variables from two different threads and are fixed in the last commit here.

mptest thread sanitizer checks that were failing in bitcoin core CI were not
failing in libmultiprocess CI, and this change instruments libcxx so the same
checks should happen both places.

Credit to MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> for pointing this out
bitcoin/bitcoin#33518 (comment)
This avoids thread sanitizer errors like:

  Read of size 8 at 0x7ffff7c81cb8 by thread T8:
    #0 std::__1::ios_base::width[abi:ne210101]() const /nix/store/71bq4557fksv43c9lf9j5ywrj6zk17hl-libcxx-21.1.1-dev/include/c++/v1/ios:497 (mptest+0x13e737)
    bitcoin-core#1 std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> > std::__1::__pad_and_output[abi:ne210101]<char, std::__1::char_traits<char> >(std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> >, char const*, char const*, char const*, std::__1::ios_base&, char) /nix/store/71bq4557fksv43c9lf9j5ywrj6zk17hl-libcxx-21.1.1-dev/include/c++/v1/__locale_dir/pad_and_output.h:54 (mptest+0x13e737)
    bitcoin-core#2 std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::__put_character_sequence[abi:ne210101]<char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*, unsigned long) /nix/store/71bq4557fksv43c9lf9j5ywrj6zk17hl-libcxx-21.1.1-dev/include/c++/v1/__ostream/put_character_sequence.h:37 (mptest+0x13e5e0)
    bitcoin-core#3 std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::operator<<[abi:ne210101]<std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*) /nix/store/71bq4557fksv43c9lf9j5ywrj6zk17hl-libcxx-21.1.1-dev/include/c++/v1/__ostream/basic_ostream.h:438 (mptest+0x13e0ee)

  Previous write of size 8 at 0x7ffff7c81cb8 by main thread (mutexes: write M0):
    #0 std::__1::ios_base::width[abi:ne210101](long) /nix/store/71bq4557fksv43c9lf9j5ywrj6zk17hl-libcxx-21.1.1-dev/include/c++/v1/ios:501 (mptest+0x13e8bc)
    bitcoin-core#1 std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> > std::__1::__pad_and_output[abi:ne210101]<char, std::__1::char_traits<char> >(std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> >, char const*, char const*, char const*, std::__1::ios_base&, char) /nix/store/71bq4557fksv43c9lf9j5ywrj6zk17hl-libcxx-21.1.1-dev/include/c++/v1/__locale_dir/pad_and_output.h:80 (mptest+0x13e8bc)
    bitcoin-core#2 std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::__put_character_sequence[abi:ne210101]<char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*, unsigned long) /nix/store/71bq4557fksv43c9lf9j5ywrj6zk17hl-libcxx-21.1.1-dev/include/c++/v1/__ostream/put_character_sequence.h:37 (mptest+0x13e5e0)
    bitcoin-core#3 std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::operator<<[abi:ne210101]<std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*) /nix/store/71bq4557fksv43c9lf9j5ywrj6zk17hl-libcxx-21.1.1-dev/include/c++/v1/__ostream/basic_ostream.h:438 (mptest+0x13e0ee)
    bitcoin-core#4 mp::test::TestSetup::TestSetup(bool)::{lambda()bitcoin-core#1}::operator()() const::{lambda(mp::LogMessage)bitcoin-core#1}::operator()(mp::LogMessage) const test/mp/test/test.cpp:71 (mptest+0x13e0ee)
New thread busy test from 1238170
(bitcoin-core#214) is checking for
"Future already retrieved" error with string match which is fragile and does
not work on all platforms, resulting in error:

test/mp/test/test.cpp:339: error: failed: expected e.what() == std::string("Future already retrieved") [std::future_error: Future already retrieved == Future already retrieved]

This change fixes the test to check for an error code instead.

Separately there seems to be a problem with this KJ_EXPECT call because it
prints error output without causing the test to fail. This may be happening
because it is not called on the main test thread. That issue is not addressed
by this change and requires more followup.
This makes libmultiprocess CI output match bitcoin core CI output and catches a
race in the new thread busy test from 1238170
(bitcoin-core#214).
New thread busy test from 1238170
(bitcoin-core#214) was triggering tsan
race errors that happen in bitcoin ci and libmultiprocess CI (after previous
commit) reported by maflcko in
bitcoin/bitcoin#33518 (comment)

The errors just happen because callback_thread and request_thread objects in
the test are accessed by two different threads: the main test thread, and the
EventLoop thread, and it is only actually safe to reference them from the
EventLoop thread.

The errors look like:

WARNING: ThreadSanitizer: data race (pid=13288)
  Write of size 4 at 0x725000000c10 by thread T13:
    #0 kj::Refcounted::disposeImpl(void*) const <null> (mptest+0x6ee095) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#1 kj::Disposer::Dispose_<capnp::ClientHook, true>::dispose(capnp::ClientHook*, kj::Disposer const&) <null> (mptest+0x2da681) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#2 void kj::Disposer::dispose<capnp::ClientHook>(capnp::ClientHook*) const <null> (mptest+0x2da5d5) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#3 kj::Own<capnp::ClientHook, std::nullptr_t>::dispose() <null> (mptest+0x2da57e) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#4 kj::Own<capnp::ClientHook, std::nullptr_t>::~Own() <null> (mptest+0x2cf135) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#5 capnp::_::(anonymous namespace)::RpcConnectionState::Export::~Export() rpc.c++ (mptest+0x32a4cc) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#6 capnp::_::(anonymous namespace)::RpcConnectionState::releaseExport(unsigned int, unsigned int) rpc.c++ (mptest+0x332ba9) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#7 capnp::_::(anonymous namespace)::RpcConnectionState::handleRelease(capnp::rpc::Release::Reader const&) rpc.c++ (mptest+0x3321ab) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#8 capnp::_::(anonymous namespace)::RpcConnectionState::handleMessage(kj::Own<capnp::IncomingRpcMessage, std::nullptr_t>) rpc.c++ (mptest+0x32eb75) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#9 capnp::_::(anonymous namespace)::RpcConnectionState::messageLoop()::'lambda'(kj::Maybe<kj::Own<capnp::IncomingRpcMessage, std::nullptr_t>>&&)::operator()(kj::Maybe<kj::Own<capnp::IncomingRpcMessage, std::nullptr_t>>&&) const rpc.c++ (mptest+0x32e75b) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#10 bool kj::_::MaybeVoidCaller<kj::Maybe<kj::Own<capnp::IncomingRpcMessage, std::nullptr_t>>, bool>::apply<capnp::_::(anonymous namespace)::RpcConnectionState::messageLoop()::'lambda'(kj::Maybe<kj::Own<capnp::IncomingRpcMessage, std::nullptr_t>>&&)>(capnp::_::(anonymous namespace)::RpcConnectionState::messageLoop()::'lambda'(kj::Maybe<kj::Own<capnp::IncomingRpcMessage, std::nullptr_t>>&&)&, kj::Maybe<kj::Own<capnp::IncomingRpcMessage, std::nullptr_t>>&&) rpc.c++ (mptest+0x393ae5) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#11 kj::_::TransformPromiseNode<bool, kj::Maybe<kj::Own<capnp::IncomingRpcMessage, std::nullptr_t>>, capnp::_::(anonymous namespace)::RpcConnectionState::messageLoop()::'lambda'(kj::Maybe<kj::Own<capnp::IncomingRpcMessage, std::nullptr_t>>&&), capnp::_::(anonymous namespace)::RpcConnectionState::messageLoop()::'lambda'(kj::Exception&&)>::getImpl(kj::_::ExceptionOrValue&) rpc.c++ (mptest+0x3936f1) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#12 kj::_::TransformPromiseNodeBase::get(kj::_::ExceptionOrValue&)::$_0::operator()() const async.c++ (mptest+0x515123) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#13 kj::Maybe<kj::Exception> kj::runCatchingExceptions<kj::_::TransformPromiseNodeBase::get(kj::_::ExceptionOrValue&)::$_0>(kj::_::TransformPromiseNodeBase::get(kj::_::ExceptionOrValue&)::$_0&&) async.c++ (mptest+0x5055e7) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#14 kj::_::TransformPromiseNodeBase::get(kj::_::ExceptionOrValue&) <null> (mptest+0x5054db) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#15 kj::_::TransformPromiseNodeBase::getDepResult(kj::_::ExceptionOrValue&) <null> (mptest+0x505892) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#16 kj::_::TransformPromiseNode<kj::_::Void, bool, capnp::_::(anonymous namespace)::RpcConnectionState::messageLoop()::'lambda'(bool), kj::_::PropagateException>::getImpl(kj::_::ExceptionOrValue&) rpc.c++ (mptest+0x395a83) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#17 kj::_::TransformPromiseNodeBase::get(kj::_::ExceptionOrValue&)::$_0::operator()() const async.c++ (mptest+0x515123) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#18 kj::Maybe<kj::Exception> kj::runCatchingExceptions<kj::_::TransformPromiseNodeBase::get(kj::_::ExceptionOrValue&)::$_0>(kj::_::TransformPromiseNodeBase::get(kj::_::ExceptionOrValue&)::$_0&&) async.c++ (mptest+0x5055e7) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#19 kj::_::TransformPromiseNodeBase::get(kj::_::ExceptionOrValue&) <null> (mptest+0x5054db) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#20 kj::TaskSet::Task::fire() <null> (mptest+0x52f703) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#21 non-virtual thunk to kj::TaskSet::Task::fire() <null> (mptest+0x52fc39) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#22 kj::EventLoop::turn() <null> (mptest+0x500065) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#23 kj::_::waitImpl(kj::Own<kj::_::PromiseNode, kj::_::PromiseDisposer>&&, kj::_::ExceptionOrValue&, kj::WaitScope&, kj::SourceLocation)::$_2::operator()() const async.c++ (mptest+0x513eb4) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#24 void kj::WaitScope::runOnStackPool<kj::_::waitImpl(kj::Own<kj::_::PromiseNode, kj::_::PromiseDisposer>&&, kj::_::ExceptionOrValue&, kj::WaitScope&, kj::SourceLocation)::$_2>(kj::_::waitImpl(kj::Own<kj::_::PromiseNode, kj::_::PromiseDisposer>&&, kj::_::ExceptionOrValue&, kj::WaitScope&, kj::SourceLocation)::$_2&&) async.c++ (mptest+0x501fd7) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#25 kj::_::waitImpl(kj::Own<kj::_::PromiseNode, kj::_::PromiseDisposer>&&, kj::_::ExceptionOrValue&, kj::WaitScope&, kj::SourceLocation) <null> (mptest+0x501b51) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#26 kj::Promise<unsigned long>::wait(kj::WaitScope&, kj::SourceLocation) /home/admin/actions-runner/_work/_temp/depends/x86_64-pc-linux-gnu/include/kj/async-inl.h:1357:3 (mptest+0x2ad447) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#27 mp::EventLoop::loop() /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/./ipc/libmultiprocess/src/mp/proxy.cpp:239:68 (mptest+0x2a836e) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#28 mp::test::TestSetup::TestSetup(bool)::'lambda'()::operator()() const /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/test/mp/test/test.cpp:99:20 (mptest+0x13f6d7) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#29 std::__1::__invoke_result_impl<void, mp::test::TestSetup::TestSetup(bool)::'lambda'()>::type std::__1::__invoke[abi:de210101]<mp::test::TestSetup::TestSetup(bool)::'lambda'()>(mp::test::TestSetup::TestSetup(bool)::'lambda'()&&) /cxx_build/include/c++/v1/__type_traits/invoke.h:87:27 (mptest+0x13edee) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#30 void std::__1::__thread_execute[abi:de210101]<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, mp::test::TestSetup::TestSetup(bool)::'lambda'()>(std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, mp::test::TestSetup::TestSetup(bool)::'lambda'()>&, std::__1::__tuple_indices<...>) /cxx_build/include/c++/v1/__thread/thread.h:159:3 (mptest+0x13edee)
    bitcoin-core#31 void* std::__1::__thread_proxy[abi:de210101]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, mp::test::TestSetup::TestSetup(bool)::'lambda'()>>(void*) /cxx_build/include/c++/v1/__thread/thread.h:168:3 (mptest+0x13edee)

  Previous write of size 4 at 0x725000000c10 by main thread (mutexes: write M0):
    #0 kj::Own<capnp::LocalClient, std::nullptr_t> kj::Refcounted::addRefInternal<capnp::LocalClient>(capnp::LocalClient*) <null> (mptest+0x303e41) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#1 kj::Own<capnp::LocalClient, std::nullptr_t> kj::addRef<capnp::LocalClient>(capnp::LocalClient&) <null> (mptest+0x30d7e2) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#2 capnp::LocalClient::addRef() <null> (mptest+0x3059f9) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#3 capnp::Capability::Client::Client(capnp::Capability::Client&) /home/admin/actions-runner/_work/_temp/depends/x86_64-pc-linux-gnu/include/capnp/capability.h:1096:68 (mptest+0x13e526) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#4 mp::Thread::Client::Client(mp::Thread::Client&) /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/include/mp/proxy.capnp.h:393:3 (mptest+0x13e526)
    bitcoin-core#5 mp::Thread::Client* std::__1::construct_at[abi:de210101]<mp::Thread::Client, mp::Thread::Client&, mp::Thread::Client*>(mp::Thread::Client*, mp::Thread::Client&) /cxx_build/include/c++/v1/__memory/construct_at.h:38:49 (mptest+0x13e526)
    bitcoin-core#6 mp::Thread::Client* std::__1::__construct_at[abi:de210101]<mp::Thread::Client, mp::Thread::Client&, mp::Thread::Client*>(mp::Thread::Client*, mp::Thread::Client&) /cxx_build/include/c++/v1/__memory/construct_at.h:46:10 (mptest+0x13e526)
    bitcoin-core#7 void std::__1::__optional_storage_base<mp::Thread::Client, false>::__construct[abi:de210101]<mp::Thread::Client&>(mp::Thread::Client&) /cxx_build/include/c++/v1/optional:371:5 (mptest+0x13e526)
    bitcoin-core#8 _ZNSt3__18optionalIN2mp6Thread6ClientEEaSB8de210101IRS3_TnNS_9enable_ifIXsr4_AndINS_17integral_constantIbXntu9__is_sameu14__remove_cvrefIT_ES4_EEEENS_7_OrImplIXaantcvbsr10_IsNotSameISA_S3_EE5valuenesZT1_Li0EEE7_ResultINS8_IbXntu9__is_sameSA_S3_EEEENS_4_NotINS_9is_scalarIS3_EEEEEENS_16is_constructibleIS3_JS9_EEENS_13is_assignableIS6_S9_EEEE5valueEiE4typeELi0EEERS4_OS9_ /cxx_build/include/c++/v1/optional:744:13 (mptest+0x13e526)
    bitcoin-core#9 mp::test::TestCase312::run() /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/test/mp/test/test.cpp:327:25 (mptest+0x136eb6) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#10 kj::TestRunner::run()::'lambda'()::operator()() const <null> (mptest+0x2bc628) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#11 kj::Maybe<kj::Exception> kj::runCatchingExceptions<kj::TestRunner::run()::'lambda'()>(kj::TestRunner::run()::'lambda'()&&) <null> (mptest+0x2b9ab7) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#12 kj::TestRunner::run() <null> (mptest+0x2b88c3) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#13 auto kj::TestRunner::getMain()::'lambda5'(auto&, auto&&...)::operator()<kj::TestRunner>(auto&, auto&&...) <null> (mptest+0x2b8161) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#14 auto kj::_::BoundMethod<kj::TestRunner&, kj::TestRunner::getMain()::'lambda5'(auto&, auto&&...), kj::TestRunner::getMain()::'lambda6'(auto&, auto&&...)>::operator()<>() <null> (mptest+0x2b80f8) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#15 kj::Function<kj::MainBuilder::Validity ()>::Impl<kj::_::BoundMethod<kj::TestRunner&, kj::TestRunner::getMain()::'lambda5'(auto&, auto&&...), kj::TestRunner::getMain()::'lambda6'(auto&, auto&&...)>>::operator()() <null> (mptest+0x2b8079) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#16 kj::Function<kj::MainBuilder::Validity ()>::operator()() <null> (mptest+0x6c9204) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#17 kj::MainBuilder::MainImpl::operator()(kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>) <null> (mptest+0x6c368d) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#18 kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>::Impl<kj::MainBuilder::MainImpl>::operator()(kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>) <null> (mptest+0x6d5e63) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#19 kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>::operator()(kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>) <null> (mptest+0x6ca206) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#20 kj::runMainAndExit(kj::ProcessContext&, kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>&&, int, char**)::$_0::operator()() const main.c++ (mptest+0x6c52d7) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#21 kj::Maybe<kj::Exception> kj::runCatchingExceptions<kj::runMainAndExit(kj::ProcessContext&, kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>&&, int, char**)::$_0>(kj::runMainAndExit(kj::ProcessContext&, kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>&&, int, char**)::$_0&&) main.c++ (mptest+0x6be577) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#22 kj::runMainAndExit(kj::ProcessContext&, kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>&&, int, char**) <null> (mptest+0x6be2db) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#23 main <null> (mptest+0x2b20d1) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)

  Location is heap block of size 512 at 0x725000000c00 allocated by thread T13:
    #0 operator new(unsigned long) <null> (mptest+0x132166) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#1 kj::Own<capnp::LocalClient, std::nullptr_t> kj::refcounted<capnp::LocalClient, kj::Own<capnp::Capability::Server, std::nullptr_t>, capnp::_::CapabilityServerSetBase&, void*&>(kj::Own<capnp::Capability::Server, std::nullptr_t>&&, capnp::_::CapabilityServerSetBase&, void*&) <null> (mptest+0x2d1a11) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#2 capnp::_::CapabilityServerSetBase::addInternal(kj::Own<capnp::Capability::Server, std::nullptr_t>&&, void*) <null> (mptest+0x2c382c) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#3 capnp::CapabilityServerSet<mp::Thread>::add(kj::Own<mp::Thread::Server, std::nullptr_t>&&) /home/admin/actions-runner/_work/_temp/depends/x86_64-pc-linux-gnu/include/capnp/capability.h:1268:10 (mptest+0x18142f) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#4 void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>&&, std::__1::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/include/mp/type-context.h:29:43 (mptest+0x1c1e51) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#5 std::__1::__invoke_result_impl<void, void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>&&, std::__1::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()&>::type std::__1::__invoke[abi:de210101]<void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>&&, std::__1::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()&>(void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>&&, std::__1::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()&) /cxx_build/include/c++/v1/__type_traits/invoke.h:87:27 (mptest+0x1c1cb3) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#6 mp::Thread::Client std::__1::__invoke_void_return_wrapper<mp::Thread::Client, false>::__call[abi:de210101]<void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>&&, std::__1::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()&>(void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>&&, std::__1::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()&) /cxx_build/include/c++/v1/__type_traits/invoke.h:334:12 (mptest+0x1c1cb3)
    bitcoin-core#7 mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>> std::__1::__invoke_r[abi:de210101]<mp::Thread::Client, void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>&&, std::__1::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()&>(void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>&&, std::__1::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()&) /cxx_build/include/c++/v1/__type_traits/invoke.h:348:10 (mptest+0x1c1cb3)
    bitcoin-core#8 std::__1::__function::__func<void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>&&, std::__1::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'(), mp::Thread::Client ()>::operator()() /cxx_build/include/c++/v1/__functional/function.h:174:12 (mptest+0x1c1cb3)
    bitcoin-core#9 std::__1::__function::__value_func<mp::Thread::Client ()>::operator()[abi:de210101]() const /cxx_build/include/c++/v1/__functional/function.h:274:12 (mptest+0x2a961f) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#10 std::__1::function<mp::Thread::Client ()>::operator()() const /cxx_build/include/c++/v1/__functional/function.h:772:10 (mptest+0x2a961f)
    bitcoin-core#11 mp::SetThread(mp::GuardedRef<std::__1::map<mp::Connection*, std::__1::optional<mp::ProxyClient<mp::Thread>>, std::__1::less<mp::Connection*>, std::__1::allocator<std::__1::pair<mp::Connection* const, std::__1::optional<mp::ProxyClient<mp::Thread>>>>>>, mp::Connection*, std::__1::function<mp::Thread::Client ()> const&) /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/./ipc/libmultiprocess/src/mp/proxy.cpp:326:32 (mptest+0x2a961f)
    bitcoin-core#12 void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>&&, std::__1::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/include/mp/type-context.h:27:31 (mptest+0x1c1554) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#13 void mp::BuildField<mp::ClientInvokeContext, mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>>(mp::TypeList<>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>&&) /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/include/mp/proxy-types.h:203:9 (mptest+0x1c0768) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#14 void mp::MaybeBuildField<mp::TypeList<>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>>(std::__1::integral_constant<bool, true>, mp::TypeList<>&&, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::foo_fields::Context, 17>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>>&&) /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/include/mp/proxy-types.h:260:5 (mptest+0x1c0768)
    bitcoin-core#15 auto void mp::ClientParam<mp::Accessor<mp::foo_fields::Context, 17>>::BuildParams::handleField<capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>, mp::TypeList<>>(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>&, mp::TypeList<>)::'lambda'<typename ...$T>($T&&...)::operator()<>($T&&...) const /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/include/mp/proxy-types.h:398:17 (mptest+0x1c0768)
    bitcoin-core#16 std::__1::__invoke_result_impl<void, $T...>::type std::__1::__invoke[abi:de210101]<void mp::ClientParam<mp::Accessor<mp::foo_fields::Context, 17>>::BuildParams::handleField<capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>, mp::TypeList<>>(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>&, mp::TypeList<>)::'lambda'<typename ...$T>($T&&...) const&>($T&&...) /cxx_build/include/c++/v1/__type_traits/invoke.h:87:27 (mptest+0x1c0768)
    bitcoin-core#17 decltype(auto) std::__1::__apply_tuple_impl[abi:de210101]<void mp::ClientParam<mp::Accessor<mp::foo_fields::Context, 17>>::BuildParams::handleField<capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>, mp::TypeList<>>(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>&, mp::TypeList<>)::'lambda'<typename ...$T>($T&&...) const&, std::__1::tuple<>>(capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>&&, mp::TypeList<>&&, std::__1::__tuple_indices<...>) /cxx_build/include/c++/v1/tuple:1380:5 (mptest+0x1c0768)
    bitcoin-core#18 decltype(auto) std::__1::apply[abi:de210101]<void mp::ClientParam<mp::Accessor<mp::foo_fields::Context, 17>>::BuildParams::handleField<capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>, mp::TypeList<>>(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>&, mp::TypeList<>)::'lambda'<typename ...$T>($T&&...) const&, std::__1::tuple<>>(capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>&&, mp::TypeList<>&&) /cxx_build/include/c++/v1/tuple:1384:5 (mptest+0x1c0768)
    bitcoin-core#19 void mp::ClientParam<mp::Accessor<mp::foo_fields::Context, 17>>::BuildParams::handleField<capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>, mp::TypeList<>>(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>&, mp::TypeList<>) /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/include/mp/proxy-types.h:409:13 (mptest+0x1c0768)
    bitcoin-core#20 void mp::IterateFieldsHelper<mp::ClientParam<mp::Accessor<mp::foo_fields::Context, 17>>::BuildParams, 0ul>::handleChain<mp::ClientInvokeContext, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>, mp::TypeList<>>(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>&, mp::TypeList<>) /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/include/mp/proxy-types.h:340:38 (mptest+0x1c0768)
    bitcoin-core#21 void mp::IterateFieldsHelper<mp::IterateFields, 0ul>::handleChain<mp::ClientInvokeContext, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>, mp::TypeList<>, mp::ClientParam<mp::Accessor<mp::foo_fields::Context, 17>>::BuildParams>(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults>&, mp::TypeList<>, mp::ClientParam<mp::Accessor<mp::foo_fields::Context, 17>>::BuildParams&&) /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/include/mp/proxy-types.h:333:17 (mptest+0x1c0768)
    bitcoin-core#22 void mp::clientInvoke<mp::ProxyClient<mp::test::messages::FooInterface>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults> (mp::test::messages::FooInterface::Client::*)(kj::Maybe<capnp::MessageSize>), mp::ClientParam<mp::Accessor<mp::foo_fields::Context, 17>>>(mp::ProxyClient<mp::test::messages::FooInterface>&, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults> (mp::test::messages::FooInterface::Client::* const&)(kj::Maybe<capnp::MessageSize>), mp::ClientParam<mp::Accessor<mp::foo_fields::Context, 17>>&&)::'lambda'()::operator()() const /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/include/mp/proxy-types.h:631:25 (mptest+0x1c0768)
    bitcoin-core#23 kj::Function<void ()>::Impl<void mp::clientInvoke<mp::ProxyClient<mp::test::messages::FooInterface>, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults> (mp::test::messages::FooInterface::Client::*)(kj::Maybe<capnp::MessageSize>), mp::ClientParam<mp::Accessor<mp::foo_fields::Context, 17>>>(mp::ProxyClient<mp::test::messages::FooInterface>&, capnp::Request<mp::test::messages::FooInterface::CallFnAsyncParams, mp::test::messages::FooInterface::CallFnAsyncResults> (mp::test::messages::FooInterface::Client::* const&)(kj::Maybe<capnp::MessageSize>), mp::ClientParam<mp::Accessor<mp::foo_fields::Context, 17>>&&)::'lambda'()>::operator()() /home/admin/actions-runner/_work/_temp/depends/x86_64-pc-linux-gnu/include/kj/function.h:142:14 (mptest+0x1c05cf) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#24 kj::Function<void ()>::operator()() /home/admin/actions-runner/_work/_temp/depends/x86_64-pc-linux-gnu/include/kj/function.h:119:12 (mptest+0x14d537) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#25 void mp::Unlock<mp::Lock, kj::Function<void ()>&>(mp::Lock&, kj::Function<void ()>&) /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/include/mp/util.h:209:5 (mptest+0x14d537)
    bitcoin-core#26 mp::EventLoop::loop() /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/./ipc/libmultiprocess/src/mp/proxy.cpp:243:13 (mptest+0x2a8425) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#27 mp::test::TestSetup::TestSetup(bool)::'lambda'()::operator()() const /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/test/mp/test/test.cpp:99:20 (mptest+0x13f6d7) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#28 std::__1::__invoke_result_impl<void, mp::test::TestSetup::TestSetup(bool)::'lambda'()>::type std::__1::__invoke[abi:de210101]<mp::test::TestSetup::TestSetup(bool)::'lambda'()>(mp::test::TestSetup::TestSetup(bool)::'lambda'()&&) /cxx_build/include/c++/v1/__type_traits/invoke.h:87:27 (mptest+0x13edee) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#29 void std::__1::__thread_execute[abi:de210101]<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, mp::test::TestSetup::TestSetup(bool)::'lambda'()>(std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, mp::test::TestSetup::TestSetup(bool)::'lambda'()>&, std::__1::__tuple_indices<...>) /cxx_build/include/c++/v1/__thread/thread.h:159:3 (mptest+0x13edee)
    bitcoin-core#30 void* std::__1::__thread_proxy[abi:de210101]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, mp::test::TestSetup::TestSetup(bool)::'lambda'()>>(void*) /cxx_build/include/c++/v1/__thread/thread.h:168:3 (mptest+0x13edee)

  Mutex M0 (0x721c00003800) created at:
    #0 pthread_mutex_lock <null> (mptest+0xaee6b) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#1 __libcpp_mutex_lock /llvm-project/libcxx/include/__thread/support/pthread.h:95:10 (libc++.so.1+0x8d059) (BuildId: 41d4816981cf4a619bef1925c75c1c35d01dfd39)
    bitcoin-core#2 std::__1::mutex::lock() /llvm-project/libcxx/src/mutex.cpp:30:12 (libc++.so.1+0x8d059)
    bitcoin-core#3 std::__1::unique_lock<std::__1::mutex>::unique_lock[abi:de210101](std::__1::mutex&) /cxx_build/include/c++/v1/__mutex/unique_lock.h:40:11 (mptest+0x154acc) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#4 mp::Lock::Lock(mp::Mutex&) /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/include/mp/util.h:172:45 (mptest+0x154acc)
    bitcoin-core#5 void mp::clientInvoke<mp::ProxyClient<mp::test::messages::FooInterface>, capnp::Request<mp::test::messages::FooInterface::AddParams, mp::test::messages::FooInterface::AddResults> (mp::test::messages::FooInterface::Client::*)(kj::Maybe<capnp::MessageSize>), mp::ClientParam<mp::Accessor<mp::foo_fields::A, 1>, int>, mp::ClientParam<mp::Accessor<mp::foo_fields::B, 1>, int>, mp::ClientParam<mp::Accessor<mp::foo_fields::Result, 2>, int&>>(mp::ProxyClient<mp::test::messages::FooInterface>&, capnp::Request<mp::test::messages::FooInterface::AddParams, mp::test::messages::FooInterface::AddResults> (mp::test::messages::FooInterface::Client::* const&)(kj::Maybe<capnp::MessageSize>), mp::ClientParam<mp::Accessor<mp::foo_fields::A, 1>, int>&&, mp::ClientParam<mp::Accessor<mp::foo_fields::B, 1>, int>&&, mp::ClientParam<mp::Accessor<mp::foo_fields::Result, 2>, int&>&&) /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/include/mp/proxy-types.h:669:10 (mptest+0x154acc)
    bitcoin-core#6 mp::ProxyClient<mp::test::messages::FooInterface>::add(int, int) /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/mp/test/foo.capnp.proxy-client.c++:20:5 (mptest+0x152b1f) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#7 mp::test::TestCase117::run() /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/test/mp/test/test.cpp:122:5 (mptest+0x13335b) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#8 kj::TestRunner::run()::'lambda'()::operator()() const <null> (mptest+0x2bc628) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#9 kj::Maybe<kj::Exception> kj::runCatchingExceptions<kj::TestRunner::run()::'lambda'()>(kj::TestRunner::run()::'lambda'()&&) <null> (mptest+0x2b9ab7) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#10 kj::TestRunner::run() <null> (mptest+0x2b88c3) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#11 auto kj::TestRunner::getMain()::'lambda5'(auto&, auto&&...)::operator()<kj::TestRunner>(auto&, auto&&...) <null> (mptest+0x2b8161) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#12 auto kj::_::BoundMethod<kj::TestRunner&, kj::TestRunner::getMain()::'lambda5'(auto&, auto&&...), kj::TestRunner::getMain()::'lambda6'(auto&, auto&&...)>::operator()<>() <null> (mptest+0x2b80f8) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#13 kj::Function<kj::MainBuilder::Validity ()>::Impl<kj::_::BoundMethod<kj::TestRunner&, kj::TestRunner::getMain()::'lambda5'(auto&, auto&&...), kj::TestRunner::getMain()::'lambda6'(auto&, auto&&...)>>::operator()() <null> (mptest+0x2b8079) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#14 kj::Function<kj::MainBuilder::Validity ()>::operator()() <null> (mptest+0x6c9204) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#15 kj::MainBuilder::MainImpl::operator()(kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>) <null> (mptest+0x6c368d) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#16 kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>::Impl<kj::MainBuilder::MainImpl>::operator()(kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>) <null> (mptest+0x6d5e63) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#17 kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>::operator()(kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>) <null> (mptest+0x6ca206) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#18 kj::runMainAndExit(kj::ProcessContext&, kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>&&, int, char**)::$_0::operator()() const main.c++ (mptest+0x6c52d7) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#19 kj::Maybe<kj::Exception> kj::runCatchingExceptions<kj::runMainAndExit(kj::ProcessContext&, kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>&&, int, char**)::$_0>(kj::runMainAndExit(kj::ProcessContext&, kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>&&, int, char**)::$_0&&) main.c++ (mptest+0x6be577) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#20 kj::runMainAndExit(kj::ProcessContext&, kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>&&, int, char**) <null> (mptest+0x6be2db) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#21 main <null> (mptest+0x2b20d1) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)

  Thread T13 (tid=13312, running) created by main thread at:
    #0 pthread_create <null> (mptest+0xad15e) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#1 std::__1::__libcpp_thread_create[abi:de210101](unsigned long*, void* (*)(void*), void*) /cxx_build/include/c++/v1/__thread/support/pthread.h:182:10 (mptest+0x13e8f0) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#2 std::__1::thread::thread[abi:de210101]<mp::test::TestSetup::TestSetup(bool)::'lambda'(), 0>(mp::test::TestSetup::TestSetup(bool)::'lambda'()&&) /cxx_build/include/c++/v1/__thread/thread.h:213:16 (mptest+0x13e8f0)
    bitcoin-core#3 mp::test::TestSetup::TestSetup(bool) /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/test/mp/test/test.cpp:69:11 (mptest+0x139f37) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#4 mp::test::TestCase312::run() /home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/test/mp/test/test.cpp:314:15 (mptest+0x136ca4) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#5 kj::TestRunner::run()::'lambda'()::operator()() const <null> (mptest+0x2bc628) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#6 kj::Maybe<kj::Exception> kj::runCatchingExceptions<kj::TestRunner::run()::'lambda'()>(kj::TestRunner::run()::'lambda'()&&) <null> (mptest+0x2b9ab7) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#7 kj::TestRunner::run() <null> (mptest+0x2b88c3) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#8 auto kj::TestRunner::getMain()::'lambda5'(auto&, auto&&...)::operator()<kj::TestRunner>(auto&, auto&&...) <null> (mptest+0x2b8161) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#9 auto kj::_::BoundMethod<kj::TestRunner&, kj::TestRunner::getMain()::'lambda5'(auto&, auto&&...), kj::TestRunner::getMain()::'lambda6'(auto&, auto&&...)>::operator()<>() <null> (mptest+0x2b80f8) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#10 kj::Function<kj::MainBuilder::Validity ()>::Impl<kj::_::BoundMethod<kj::TestRunner&, kj::TestRunner::getMain()::'lambda5'(auto&, auto&&...), kj::TestRunner::getMain()::'lambda6'(auto&, auto&&...)>>::operator()() <null> (mptest+0x2b8079) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#11 kj::Function<kj::MainBuilder::Validity ()>::operator()() <null> (mptest+0x6c9204) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#12 kj::MainBuilder::MainImpl::operator()(kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>) <null> (mptest+0x6c368d) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#13 kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>::Impl<kj::MainBuilder::MainImpl>::operator()(kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>) <null> (mptest+0x6d5e63) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#14 kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>::operator()(kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>) <null> (mptest+0x6ca206) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#15 kj::runMainAndExit(kj::ProcessContext&, kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>&&, int, char**)::$_0::operator()() const main.c++ (mptest+0x6c52d7) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#16 kj::Maybe<kj::Exception> kj::runCatchingExceptions<kj::runMainAndExit(kj::ProcessContext&, kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>&&, int, char**)::$_0>(kj::runMainAndExit(kj::ProcessContext&, kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>&&, int, char**)::$_0&&) main.c++ (mptest+0x6be577) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#17 kj::runMainAndExit(kj::ProcessContext&, kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>&&, int, char**) <null> (mptest+0x6be2db) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)
    bitcoin-core#18 main <null> (mptest+0x2b20d1) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d)

SUMMARY: ThreadSanitizer: data race (/home/admin/actions-runner/_work/_temp/build/src/ipc/libmultiprocess/test/mptest+0x6ee095) (BuildId: 0a10180b43648715b83845ce52ff1702609db59d) in kj::Refcounted::disposeImpl(void*) const
@DrahtBot
Copy link

DrahtBot commented Oct 2, 2025

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Reviews

See the guideline for information on the review process.
A summary of reviews will appear here.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #218 (Better error and log messages by ryanofsky)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@ryanofsky
Copy link
Collaborator Author

Updated 1cfe541 -> 73d22ba (pr/san.1 -> pr/san.2, compare) fixing IWYU errors

@theuni
Copy link
Contributor

theuni commented Oct 2, 2025

The errors just happen because callback_thread and request_thread objects in the test are accessed by two different threads: the main test thread, and the EventLoop thread, and it is only actually safe to reference them from the EventLoop thread.

Would it be possible to add threading annotations to enforce this contract? For ex, adding a private dummy mutex, guarding the vulnerable variables with it, and holding that mutex for the duration of the EventLoop thread? We use that trick (g_msgproc_mutex) in Core to enforce a similar contract.

(Technically clang doesn't require a real mutex, only a capability, so the dummy could just be an int. But as there's no actual contention, using a real mutex seems fine imo).

TestSetup(bool client_owns_connection = true)
: thread{[&] {
EventLoop loop("mptest", [](mp::LogMessage log_data) {
std::cout << "LOG" << (int)log_data.level << ": " << log_data.message << "\n";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing this. This was a placeholder that I forgot to revisit.

@ryanofsky
Copy link
Collaborator Author

ryanofsky commented Oct 2, 2025

Would it be possible to add threading annotations to enforce this contract? For ex, adding a private dummy mutex, guarding the vulnerable variables with it, and holding that mutex for the duration of the EventLoop thread? We use that trick (g_msgproc_mutex) in Core to enforce a similar contract.

I think that trick might not apply exactly because the state here is internal to cap'nproto, and cap'nproto is single threaded and doesn't use any thread synchronization or mutexes itself. The requirement that needs to be enforced is that any capnproto function which might trigger IO (including some capnproto object destructors in this case) need to be called from the EventLoop thread with the EventLoop::sync method.

I imagine there could be compile time checks to enforce this (maybe using a pointer-like object overloading * and -> to wrap capnproto objects) but I don't have a clear idea of what it would look like. Does seem worth thinking about.

ryanofsky added a commit to ryanofsky/libmultiprocess that referenced this pull request Oct 3, 2025
@ryanofsky ryanofsky mentioned this pull request Oct 3, 2025
@ryanofsky
Copy link
Collaborator Author

re: #222 (comment)

Would it be possible to add threading annotations to enforce this contract?

Was thinking about this a little more, and I think an approach that could work could be to have a LoopObj<T> struct with T and EventLoop& members and * and -> operators returning T& and requiring requiring a TSA capability to dereference. The EventLoop object could be the capability object, or it could have a dummy member that's is marked as a capability. Then there could be a dummy locking object to acquire the capability, just asserting the current thread is the event loop thread when constructed.

Concretely then if the ProxyClientBase::m_client variable were declared with LoopObj<Interface::Client> type instead of Interface::Client type, the race in the #214 test wouldn't have happened because the callback_thread and request_thread variables would be protected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants