refactor: memcpy to std::ranges::copy to work around ubsan warn #305

pull maflcko wants to merge 1 commits into bitcoin-core:master from maflcko:2607-ubsan-memcpy-null-warn changing 4 files +7 −1
  1. maflcko commented at 6:05 PM on July 9, 2026: contributor

    Using std::ranges::copy from the C++ standard library has a few benefits here:

    • It has the additional benefit of being a bit more type safe and document any needed cast explicitly. (No cast is needed here)
    • It has defined semantics for empty source ranges.

    This should also fix https://github.com/bitcoin/bitcoin/pull/35118#discussion_r3506566815

  2. DrahtBot commented at 6:05 PM on July 9, 2026: none

    <!--e57a25ab6845829454e8d69fc972939a-->

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

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline and AI policy for information on the review process.

    Type Reviewers
    ACK Sjors, ViniciusCestarii, ryanofsky

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  3. refactor: memcpy to std::ranges::copy to work around ubsan warn fac7b9b7f6
  4. maflcko force-pushed on Jul 9, 2026
  5. maflcko commented at 6:07 PM on July 9, 2026: contributor

    Failure should look roughly like:

    # cmake --build build-ubsan-gcc --target tests && UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=0:report_error_type=1" ./build-ubsan-gcc/test/mptest 
    ninja: no work to do.
    [ TEST ] listen_tests.cpp:214: ListenConnections accepts incoming connections
    [ PASS ] listen_tests.cpp:214: ListenConnections accepts incoming connections (18477 μs)
    [ TEST ] listen_tests.cpp:224: ListenConnections enforces a local connection limit
    [ PASS ] listen_tests.cpp:224: ListenConnections enforces a local connection limit (18818 μs)
    [ TEST ] listen_tests.cpp:262: ListenConnections accepts multiple connections
    [ PASS ] listen_tests.cpp:262: ListenConnections accepts multiple connections (9224 μs)
    [ TEST ] spawn_tests.cpp:46: SpawnProcess does not run callback in child
    [ PASS ] spawn_tests.cpp:46: SpawnProcess does not run callback in child (138059 μs)
    [ TEST ] test.cpp:143: Call FooInterface methods
    /tmp/tmp.sFxQecaMfz/git_dir/include/mp/type-data.h:36:11: runtime error: null pointer passed as argument 2, which is declared to never be null
        [#0](/bitcoin-core-multiprocess/0/) 0x61583eb6352f in _ZN2mp16CustomBuildFieldISt6vectorIcSaIcEES3_NS_11StructFieldINS_8AccessorINS_10foo_fields3ArgELi17EEEN5capnp7RequestINS_4test8messages12FooInterface14PassDataParamsENSD_15PassDataResultsEEEEEEEvNS_8TypeListIJT_EEENS_8PriorityILi2EEERNS_13InvokeContextEOT0_OT1_Qaa9is_same_vIDTcldtfL0p3_3getEENS9_4Data7BuilderEE10IsByteSpanISJ_E /tmp/tmp.sFxQecaMfz/git_dir/include/mp/type-data.h:36
        [#1](/bitcoin-core-multiprocess/1/) 0x61583eb45ee2 in void mp::BuildField<std::vector<char, std::allocator<char> >, mp::ClientInvokeContext, std::vector<char, std::allocator<char> >, mp::StructField<mp::Accessor<mp::foo_fields::Arg, 17>, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults> > >(mp::TypeList<std::vector<char, std::allocator<char> > >, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::foo_fields::Arg, 17>, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults> >&&, std::vector<char, std::allocator<char> >&&) /tmp/tmp.sFxQecaMfz/git_dir/include/mp/proxy-types.h:253
        [#2](/bitcoin-core-multiprocess/2/) 0x61583eb1dcad in void mp::MaybeBuildField<mp::TypeList<std::vector<char, std::allocator<char> > >, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::foo_fields::Arg, 17>, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults> >, std::vector<char, std::allocator<char> > >(std::integral_constant<bool, true>, mp::TypeList<std::vector<char, std::allocator<char> > >&&, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::foo_fields::Arg, 17>, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults> >&&, std::vector<char, std::allocator<char> >&&) /tmp/tmp.sFxQecaMfz/git_dir/include/mp/proxy-types.h:336
        [#3](/bitcoin-core-multiprocess/3/) 0x61583eaeacc0 in auto mp::ClientParam<mp::Accessor<mp::foo_fields::Arg, 17>, std::vector<char, std::allocator<char> > >::BuildParams::handleField<capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>, mp::TypeList<std::vector<char, std::allocator<char> > > >(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&, mp::TypeList<std::vector<char, std::allocator<char> > >)::{lambda<typename... $T0>(($T0&&)...)#1}::operator()<std::vector<char, std::allocator<char> > >(std::vector<char, std::allocator<char> >&&) const /tmp/tmp.sFxQecaMfz/git_dir/include/mp/proxy-types.h:474
        [#4](/bitcoin-core-multiprocess/4/) 0x61583eb4601d in void std::__invoke_impl<void, mp::ClientParam<mp::Accessor<mp::foo_fields::Arg, 17>, std::vector<char, std::allocator<char> > >::BuildParams::handleField<capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>, mp::TypeList<std::vector<char, std::allocator<char> > > >(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&, mp::TypeList<std::vector<char, std::allocator<char> > >)::{lambda<typename... $T0>(($T0&&)...)#1} const&, std::vector<char, std::allocator<char> > >(std::__invoke_other, mp::ClientParam<mp::Accessor<mp::foo_fields::Arg, 17>, std::vector<char, std::allocator<char> > >::BuildParams::handleField<capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>, mp::TypeList<std::vector<char, std::allocator<char> > > >(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&, mp::TypeList<std::vector<char, std::allocator<char> > >)::{lambda<typename... $T0>(($T0&&)...)#1} const&, std::vector<char, std::allocator<char> >&&) /usr/include/c++/15/bits/invoke.h:63
        [#5](/bitcoin-core-multiprocess/5/) 0x61583eb1de59 in std::__invoke_result<mp::ClientParam<mp::Accessor<mp::foo_fields::Arg, 17>, std::vector<char, std::allocator<char> > >::BuildParams::handleField<capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>, mp::TypeList<std::vector<char, std::allocator<char> > > >(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&, mp::TypeList<std::vector<char, std::allocator<char> > >)::{lambda<typename... $T0>(($T0&&)...)#1} const&, std::vector<char, std::allocator<char> > >::type std::__invoke<mp::ClientParam<mp::Accessor<mp::foo_fields::Arg, 17>, std::vector<char, std::allocator<char> > >::BuildParams::handleField<capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>, mp::TypeList<std::vector<char, std::allocator<char> > > >(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&, mp::TypeList<std::vector<char, std::allocator<char> > >)::{lambda<typename... $T0>(($T0&&)...)#1} const&, std::vector<char, std::allocator<char> > >(capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&&, std::vector<char, std::allocator<char> >&&) /usr/include/c++/15/bits/invoke.h:98
        [#6](/bitcoin-core-multiprocess/6/) 0x61583eaeadc1 in decltype(auto) std::__apply_impl<mp::ClientParam<mp::Accessor<mp::foo_fields::Arg, 17>, std::vector<char, std::allocator<char> > >::BuildParams::handleField<capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>, mp::TypeList<std::vector<char, std::allocator<char> > > >(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&, mp::TypeList<std::vector<char, std::allocator<char> > >)::{lambda<typename... $T0>(($T0&&)...)#1} const&, std::tuple<std::vector<char, std::allocator<char> >&&>, 0ul>(capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&&, std::tuple<std::vector<char, std::allocator<char> >&&>&&, std::integer_sequence<unsigned long, 0ul>) /usr/include/c++/15/tuple:2920
        [#7](/bitcoin-core-multiprocess/7/) 0x61583eaeaea0 in decltype(auto) std::apply<mp::ClientParam<mp::Accessor<mp::foo_fields::Arg, 17>, std::vector<char, std::allocator<char> > >::BuildParams::handleField<capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>, mp::TypeList<std::vector<char, std::allocator<char> > > >(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&, mp::TypeList<std::vector<char, std::allocator<char> > >)::{lambda<typename... $T0>(($T0&&)...)#1} const&, std::tuple<std::vector<char, std::allocator<char> >&&> >(capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&&, std::tuple<std::vector<char, std::allocator<char> >&&>&&) /usr/include/c++/15/tuple:2935
        [#8](/bitcoin-core-multiprocess/8/) 0x61583eaeafbc in void mp::ClientParam<mp::Accessor<mp::foo_fields::Arg, 17>, std::vector<char, std::allocator<char> > >::BuildParams::handleField<capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>, mp::TypeList<std::vector<char, std::allocator<char> > > >(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&, mp::TypeList<std::vector<char, std::allocator<char> > >) /tmp/tmp.sFxQecaMfz/git_dir/include/mp/proxy-types.h:485
        [#9](/bitcoin-core-multiprocess/9/) 0x61583eaaf470 in void mp::IterateFieldsHelper<mp::ClientParam<mp::Accessor<mp::foo_fields::Arg, 17>, std::vector<char, std::allocator<char> > >::BuildParams, 1ul>::handleChain<mp::ClientInvokeContext, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>, mp::TypeList<std::vector<char, std::allocator<char> > > >(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&, mp::TypeList<std::vector<char, std::allocator<char> > >) /tmp/tmp.sFxQecaMfz/git_dir/include/mp/proxy-types.h:416
        [#10](/bitcoin-core-multiprocess/10/) 0x61583ea8b2b7 in void mp::IterateFieldsHelper<mp::ClientParam<mp::Accessor<mp::foo_fields::Arg, 17>, std::vector<char, std::allocator<char> > >::BuildParams, 1ul>::handleChain<mp::ClientInvokeContext, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>, mp::TypeList<std::vector<char, std::allocator<char> >, std::vector<char, std::allocator<char> > >, mp::ClientParam<mp::Accessor<mp::foo_fields::Result, 18>, std::vector<char, std::allocator<char> >&>::BuildParams>(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&, mp::TypeList<std::vector<char, std::allocator<char> >, std::vector<char, std::allocator<char> > >, mp::ClientParam<mp::Accessor<mp::foo_fields::Result, 18>, std::vector<char, std::allocator<char> >&>::BuildParams&&) /tmp/tmp.sFxQecaMfz/git_dir/include/mp/proxy-types.h:408
        [#11](/bitcoin-core-multiprocess/11/) 0x61583ea6abc4 in void mp::IterateFieldsHelper<mp::IterateFields, 0ul>::handleChain<mp::ClientInvokeContext, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>, mp::TypeList<std::vector<char, std::allocator<char> >, std::vector<char, std::allocator<char> > >, mp::ClientParam<mp::Accessor<mp::foo_fields::Arg, 17>, std::vector<char, std::allocator<char> > >::BuildParams, mp::ClientParam<mp::Accessor<mp::foo_fields::Result, 18>, std::vector<char, std::allocator<char> >&>::BuildParams>(mp::ClientInvokeContext&, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&, mp::TypeList<std::vector<char, std::allocator<char> >, std::vector<char, std::allocator<char> > >, mp::ClientParam<mp::Accessor<mp::foo_fields::Arg, 17>, std::vector<char, std::allocator<char> > >::BuildParams&&, mp::ClientParam<mp::Accessor<mp::foo_fields::Result, 18>, std::vector<char, std::allocator<char> >&>::BuildParams&&) /tmp/tmp.sFxQecaMfz/git_dir/include/mp/proxy-types.h:409
        [#12](/bitcoin-core-multiprocess/12/) 0x61583ea27feb in mp::clientInvoke<mp::ProxyClient<mp::test::messages::FooInterface>, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults> (mp::test::messages::FooInterface::Client::*)(kj::Maybe<capnp::MessageSize>), mp::ClientParam<mp::Accessor<mp::foo_fields::Arg, 17>, std::vector<char, std::allocator<char> > >, mp::ClientParam<mp::Accessor<mp::foo_fields::Result, 18>, std::vector<char, std::allocator<char> >&> >(mp::ProxyClient<mp::test::messages::FooInterface>&, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults> (mp::test::messages::FooInterface::Client::* const&)(kj::Maybe<capnp::MessageSize>), mp::ClientParam<mp::Accessor<mp::foo_fields::Arg, 17>, std::vector<char, std::allocator<char> > >&&, mp::ClientParam<mp::Accessor<mp::foo_fields::Result, 18>, std::vector<char, std::allocator<char> >&>&&)::{lambda()#1}::operator()() const /tmp/tmp.sFxQecaMfz/git_dir/include/mp/proxy-types.h:730
        [#13](/bitcoin-core-multiprocess/13/) 0x61583ebbb923 in kj::Function<void ()>::Impl<mp::clientInvoke<mp::ProxyClient<mp::test::messages::FooInterface>, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults> (mp::test::messages::FooInterface::Client::*)(kj::Maybe<capnp::MessageSize>), mp::ClientParam<mp::Accessor<mp::foo_fields::Arg, 17>, std::vector<char, std::allocator<char> > >, mp::ClientParam<mp::Accessor<mp::foo_fields::Result, 18>, std::vector<char, std::allocator<char> >&> >(mp::ProxyClient<mp::test::messages::FooInterface>&, capnp::Request<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults> (mp::test::messages::FooInterface::Client::* const&)(kj::Maybe<capnp::MessageSize>), mp::ClientParam<mp::Accessor<mp::foo_fields::Arg, 17>, std::vector<char, std::allocator<char> > >&&, mp::ClientParam<mp::Accessor<mp::foo_fields::Result, 18>, std::vector<char, std::allocator<char> >&>&&)::{lambda()#1}>::operator()() /usr/include/kj/function.h:142
        [#14](/bitcoin-core-multiprocess/14/) 0x61583e95004c in kj::Function<void ()>::operator()() /usr/include/kj/function.h:119
        [#15](/bitcoin-core-multiprocess/15/) 0x61583e941e89 in void mp::Unlock<mp::Lock, kj::Function<void ()>&>(mp::Lock&, kj::Function<void ()>&) /tmp/tmp.sFxQecaMfz/git_dir/include/mp/util.h:216
        [#16](/bitcoin-core-multiprocess/16/) 0x61583f10d034 in operator() /tmp/tmp.sFxQecaMfz/git_dir/src/mp/proxy.cpp:254
        [#17](/bitcoin-core-multiprocess/17/) 0x61583f1176e2 in runCatchingExceptions<mp::EventLoop::loop()::<lambda()> > /usr/include/kj/exception.h:371
        [#18](/bitcoin-core-multiprocess/18/) 0x61583f10d926 in mp::EventLoop::loop() /tmp/tmp.sFxQecaMfz/git_dir/src/mp/proxy.cpp:254
        [#19](/bitcoin-core-multiprocess/19/) 0x61583e9153aa in mp::test::TestSetup::TestSetup(bool)::{lambda()#1}::operator()() const /tmp/tmp.sFxQecaMfz/git_dir/test/mp/test/test.cpp:125
        [#20](/bitcoin-core-multiprocess/20/) 0x61583e97cacc in void std::__invoke_impl<void, mp::test::TestSetup::TestSetup(bool)::{lambda()#1}>(std::__invoke_other, mp::test::TestSetup::TestSetup(bool)::{lambda()#1}&&) /usr/include/c++/15/bits/invoke.h:63
        [#21](/bitcoin-core-multiprocess/21/) 0x61583e97adaf in std::__invoke_result<mp::test::TestSetup::TestSetup(bool)::{lambda()#1}>::type std::__invoke<mp::test::TestSetup::TestSetup(bool)::{lambda()#1}>(mp::test::TestSetup::TestSetup(bool)::{lambda()#1}&&) /usr/include/c++/15/bits/invoke.h:98
        [#22](/bitcoin-core-multiprocess/22/) 0x61583e979782 in void std::thread::_Invoker<std::tuple<mp::test::TestSetup::TestSetup(bool)::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/include/c++/15/bits/std_thread.h:303
        [#23](/bitcoin-core-multiprocess/23/) 0x61583e977a97 in std::thread::_Invoker<std::tuple<mp::test::TestSetup::TestSetup(bool)::{lambda()#1}> >::operator()() /usr/include/c++/15/bits/std_thread.h:310
        [#24](/bitcoin-core-multiprocess/24/) 0x61583e976029 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<mp::test::TestSetup::TestSetup(bool)::{lambda()#1}> > >::_M_run() /usr/include/c++/15/bits/std_thread.h:255
        [#25](/bitcoin-core-multiprocess/25/) 0x7da055842ef8  (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xf5ef8) (BuildId: 3a7a8c6bd922e6314edb7a710fdc0293265c2c42)
        [#26](/bitcoin-core-multiprocess/26/) 0x7da054e5f0d9  (/usr/lib/x86_64-linux-gnu/libc.so.6+0xa40d9) (BuildId: 90ebd03ae9d9f42b23b4eb82fdf70352cf744198)
        [#27](/bitcoin-core-multiprocess/27/) 0x7da054ef27ab  (/usr/lib/x86_64-linux-gnu/libc.so.6+0x1377ab) (BuildId: 90ebd03ae9d9f42b23b4eb82fdf70352cf744198)
    
    /tmp/tmp.sFxQecaMfz/git_dir/include/mp/type-data.h:36:11: runtime error: null pointer passed as argument 2, which is declared to never be null
        [#0](/bitcoin-core-multiprocess/0/) 0x61583ee75afc in _ZN2mp16CustomBuildFieldIOSt6vectorIcSaIcEES3_NS_11StructFieldINS_8AccessorINS_10foo_fields6ResultELi18EEENS_4test8messages12FooInterface15PassDataResults7BuilderEEEEEvNS_8TypeListIJT_EEENS_8PriorityILi2EEERNS_13InvokeContextEOT0_OT1_Qaa9is_same_vIDTcldtfL0p3_3getEEN5capnp4Data7BuilderEE10IsByteSpanISH_E /tmp/tmp.sFxQecaMfz/git_dir/include/mp/type-data.h:36
        [#1](/bitcoin-core-multiprocess/1/) 0x61583edf4f7a in void mp::BuildField<std::vector<char, std::allocator<char> >&&, mp::InvokeContext, std::vector<char, std::allocator<char> >, mp::StructField<mp::Accessor<mp::foo_fields::Result, 18>, mp::test::messages::FooInterface::PassDataResults::Builder> >(mp::TypeList<std::vector<char, std::allocator<char> >&&>, mp::InvokeContext&, mp::StructField<mp::Accessor<mp::foo_fields::Result, 18>, mp::test::messages::FooInterface::PassDataResults::Builder>&&, std::vector<char, std::allocator<char> >&&) /tmp/tmp.sFxQecaMfz/git_dir/include/mp/proxy-types.h:253
        [#2](/bitcoin-core-multiprocess/2/) 0x61583ed74581 in void mp::ServerRet<mp::Accessor<mp::foo_fields::Result, 18>, mp::ServerCall>::invoke<mp::ServerInvokeContext<mp::ProxyServer<mp::test::messages::FooInterface>, capnp::CallContext<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults> >, std::vector<char, std::allocator<char> > >(mp::ServerInvokeContext<mp::ProxyServer<mp::test::messages::FooInterface>, capnp::CallContext<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults> >&, mp::TypeList<>, std::vector<char, std::allocator<char> >&&) const /tmp/tmp.sFxQecaMfz/git_dir/include/mp/proxy-types.h:577
        [#3](/bitcoin-core-multiprocess/3/) 0x61583ecdfeb2 in void mp::PassField<mp::Accessor<mp::foo_fields::Arg, 17>, std::vector<char, std::allocator<char> >, mp::ServerInvokeContext<mp::ProxyServer<mp::test::messages::FooInterface>, capnp::CallContext<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults> >, mp::ServerRet<mp::Accessor<mp::foo_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<> >(mp::Priority<0>, mp::TypeList<std::vector<char, std::allocator<char> > >, mp::ServerInvokeContext<mp::ProxyServer<mp::test::messages::FooInterface>, capnp::CallContext<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults> >&, mp::ServerRet<mp::Accessor<mp::foo_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&) /tmp/tmp.sFxQecaMfz/git_dir/include/mp/proxy-types.h:383
        [#4](/bitcoin-core-multiprocess/4/) 0x61583ec6b087 in decltype(auto) mp::ServerField<1, mp::Accessor<mp::foo_fields::Arg, 17>, mp::ServerRet<mp::Accessor<mp::foo_fields::Result, 18>, mp::ServerCall> >::invoke<mp::ServerInvokeContext<mp::ProxyServer<mp::test::messages::FooInterface>, capnp::CallContext<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults> >, mp::TypeList<std::vector<char, std::allocator<char> > >>(mp::ServerInvokeContext<mp::ProxyServer<mp::test::messages::FooInterface>, capnp::CallContext<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults> >&, mp::TypeList<std::vector<char, std::allocator<char> > >) const /tmp/tmp.sFxQecaMfz/git_dir/include/mp/proxy-types.h:642
        [#5](/bitcoin-core-multiprocess/5/) 0x61583ec6b01c in mp::serverInvoke<mp::ProxyServer<mp::test::messages::FooInterface>, capnp::CallContext<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>, mp::ServerField<1, mp::Accessor<mp::foo_fields::Arg, 17>, mp::ServerRet<mp::Accessor<mp::foo_fields::Result, 18>, mp::ServerCall> > >(mp::ProxyServer<mp::test::messages::FooInterface>&, capnp::CallContext<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&, mp::ServerField<1, mp::Accessor<mp::foo_fields::Arg, 17>, mp::ServerRet<mp::Accessor<mp::foo_fields::Result, 18>, mp::ServerCall> >)::{lambda()#1}::operator()() const /tmp/tmp.sFxQecaMfz/git_dir/include/mp/proxy-types.h:823
        [#6](/bitcoin-core-multiprocess/6/) 0x61583ec6b234 in auto mp::ReplaceVoid<mp::serverInvoke<mp::ProxyServer<mp::test::messages::FooInterface>, capnp::CallContext<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>, mp::ServerField<1, mp::Accessor<mp::foo_fields::Arg, 17>, mp::ServerRet<mp::Accessor<mp::foo_fields::Result, 18>, mp::ServerCall> > >(mp::ProxyServer<mp::test::messages::FooInterface>&, capnp::CallContext<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&, mp::ServerField<1, mp::Accessor<mp::foo_fields::Arg, 17>, mp::ServerRet<mp::Accessor<mp::foo_fields::Result, 18>, mp::ServerCall> >)::{lambda()#1}, mp::serverInvoke<mp::ProxyServer<mp::test::messages::FooInterface>, capnp::CallContext<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>, mp::ServerField<1, mp::Accessor<mp::foo_fields::Arg, 17>, mp::ServerRet<mp::Accessor<mp::foo_fields::Result, 18>, mp::ServerCall> > >(mp::ProxyServer<mp::test::messages::FooInterface>&, capnp::CallContext<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&, mp::ServerField<1, mp::Accessor<mp::foo_fields::Arg, 17>, mp::ServerRet<mp::Accessor<mp::foo_fields::Result, 18>, mp::ServerCall> >)::{lambda()#2}>(mp::ProxyServer<mp::test::messages::FooInterface>&&, capnp::CallContext<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&&) /tmp/tmp.sFxQecaMfz/git_dir/include/mp/proxy-types.h:782
        [#7](/bitcoin-core-multiprocess/7/) 0x61583ec6c6df in kj::Promise<void> mp::serverInvoke<mp::ProxyServer<mp::test::messages::FooInterface>, capnp::CallContext<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>, mp::ServerField<1, mp::Accessor<mp::foo_fields::Arg, 17>, mp::ServerRet<mp::Accessor<mp::foo_fields::Result, 18>, mp::ServerCall> > >(mp::ProxyServer<mp::test::messages::FooInterface>&, capnp::CallContext<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>&, mp::ServerField<1, mp::Accessor<mp::foo_fields::Arg, 17>, mp::ServerRet<mp::Accessor<mp::foo_fields::Result, 18>, mp::ServerCall> >) /tmp/tmp.sFxQecaMfz/git_dir/include/mp/proxy-types.h:823
        [#8](/bitcoin-core-multiprocess/8/) 0x61583ec161b5 in mp::ProxyServer<mp::test::messages::FooInterface>::passData(capnp::CallContext<mp::test::messages::FooInterface::PassDataParams, mp::test::messages::FooInterface::PassDataResults>) /tmp/tmp.sFxQecaMfz/git_dir/build-ubsan-gcc/test/mp/test/foo.capnp.proxy-server.c++:93
        [#9](/bitcoin-core-multiprocess/9/) 0x61583e991105 in mp::test::messages::FooInterface::Server::dispatchCallInternal(unsigned short, capnp::CallContext<capnp::AnyPointer, capnp::AnyPointer>) /tmp/tmp.sFxQecaMfz/git_dir/build-ubsan-gcc/test/mp/test/foo.capnp.c++:4642
        [#10](/bitcoin-core-multiprocess/10/) 0x61583e984728 in mp::test::messages::FooInterface::Server::dispatchCall(unsigned long, unsigned short, capnp::CallContext<capnp::AnyPointer, capnp::AnyPointer>) /tmp/tmp.sFxQecaMfz/git_dir/build-ubsan-gcc/test/mp/test/foo.capnp.c++:4452
        [#11](/bitcoin-core-multiprocess/11/) 0x7da055c49874  (/usr/lib/x86_64-linux-gnu/libcapnp-rpc-1.1.0.so+0x58874) (BuildId: 4bc3b60e77961fd7bf5b0656724a4b009a1cdc60)
        [#12](/bitcoin-core-multiprocess/12/) 0x7da055c58933  (/usr/lib/x86_64-linux-gnu/libcapnp-rpc-1.1.0.so+0x67933) (BuildId: 4bc3b60e77961fd7bf5b0656724a4b009a1cdc60)
        [#13](/bitcoin-core-multiprocess/13/) 0x7da055ab51bd in kj::_::TransformPromiseNodeBase::get(kj::_::ExceptionOrValue&) (/usr/lib/x86_64-linux-gnu/libkj-async-1.1.0.so+0x421bd) (BuildId: 11e33396b3aedb25ab73f8c546c7af5db001c789)
        [#14](/bitcoin-core-multiprocess/14/) 0x7da055abff57 in kj::_::ChainPromiseNode::fire() (/usr/lib/x86_64-linux-gnu/libkj-async-1.1.0.so+0x4cf57) (BuildId: 11e33396b3aedb25ab73f8c546c7af5db001c789)
        [#15](/bitcoin-core-multiprocess/15/) 0x7da055aac852 in kj::EventLoop::turn() (/usr/lib/x86_64-linux-gnu/libkj-async-1.1.0.so+0x39852) (BuildId: 11e33396b3aedb25ab73f8c546c7af5db001c789)
        [#16](/bitcoin-core-multiprocess/16/) 0x7da055ab2968 in kj::_::waitImpl(kj::Own<kj::_::PromiseNode, kj::_::PromiseDisposer>&&, kj::_::ExceptionOrValue&, kj::WaitScope&, kj::SourceLocation) (/usr/lib/x86_64-linux-gnu/libkj-async-1.1.0.so+0x3f968) (BuildId: 11e33396b3aedb25ab73f8c546c7af5db001c789)
        [#17](/bitcoin-core-multiprocess/17/) 0x61583f1239ea in kj::Promise<unsigned long>::wait(kj::WaitScope&, kj::SourceLocation) /usr/include/kj/async-inl.h:1357
        [#18](/bitcoin-core-multiprocess/18/) 0x61583f10d753 in mp::EventLoop::loop() /tmp/tmp.sFxQecaMfz/git_dir/src/mp/proxy.cpp:247
        [#19](/bitcoin-core-multiprocess/19/) 0x61583e9153aa in mp::test::TestSetup::TestSetup(bool)::{lambda()#1}::operator()() const /tmp/tmp.sFxQecaMfz/git_dir/test/mp/test/test.cpp:125
        [#20](/bitcoin-core-multiprocess/20/) 0x61583e97cacc in void std::__invoke_impl<void, mp::test::TestSetup::TestSetup(bool)::{lambda()#1}>(std::__invoke_other, mp::test::TestSetup::TestSetup(bool)::{lambda()#1}&&) /usr/include/c++/15/bits/invoke.h:63
        [#21](/bitcoin-core-multiprocess/21/) 0x61583e97adaf in std::__invoke_result<mp::test::TestSetup::TestSetup(bool)::{lambda()#1}>::type std::__invoke<mp::test::TestSetup::TestSetup(bool)::{lambda()#1}>(mp::test::TestSetup::TestSetup(bool)::{lambda()#1}&&) /usr/include/c++/15/bits/invoke.h:98
        [#22](/bitcoin-core-multiprocess/22/) 0x61583e979782 in void std::thread::_Invoker<std::tuple<mp::test::TestSetup::TestSetup(bool)::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/include/c++/15/bits/std_thread.h:303
        [#23](/bitcoin-core-multiprocess/23/) 0x61583e977a97 in std::thread::_Invoker<std::tuple<mp::test::TestSetup::TestSetup(bool)::{lambda()#1}> >::operator()() /usr/include/c++/15/bits/std_thread.h:310
        [#24](/bitcoin-core-multiprocess/24/) 0x61583e976029 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<mp::test::TestSetup::TestSetup(bool)::{lambda()#1}> > >::_M_run() /usr/include/c++/15/bits/std_thread.h:255
        [#25](/bitcoin-core-multiprocess/25/) 0x7da055842ef8  (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xf5ef8) (BuildId: 3a7a8c6bd922e6314edb7a710fdc0293265c2c42)
        [#26](/bitcoin-core-multiprocess/26/) 0x7da054e5f0d9  (/usr/lib/x86_64-linux-gnu/libc.so.6+0xa40d9) (BuildId: 90ebd03ae9d9f42b23b4eb82fdf70352cf744198)
        [#27](/bitcoin-core-multiprocess/27/) 0x7da054ef27ab  (/usr/lib/x86_64-linux-gnu/libc.so.6+0x1377ab) (BuildId: 90ebd03ae9d9f42b23b4eb82fdf70352cf744198)
    
    [ PASS ] test.cpp:143: Call FooInterface methods (627953 μs)
    [ TEST ] test.cpp:274: Call IPC method after client connection is closed
    [ PASS ] test.cpp:274: Call IPC method after client connection is closed (3349 μs)
    [ TEST ] test.cpp:284: Calling IPC method after server connection is closed
    [ PASS ] test.cpp:284: Calling IPC method after server connection is closed (4292 μs)
    [ TEST ] test.cpp:294: Calling IPC method and disconnecting during the call
    [ PASS ] test.cpp:294: Calling IPC method and disconnecting during the call (5566 μs)
    [ TEST ] test.cpp:307: Calling IPC method, disconnecting and blocking during the call
    [ PASS ] test.cpp:307: Calling IPC method, disconnecting and blocking during the call (11115 μs)
    [ TEST ] test.cpp:349: Worker thread destroyed before it is initialized
    [ PASS ] test.cpp:349: Worker thread destroyed before it is initialized (21340 μs)
    [ TEST ] test.cpp:379: Calling async IPC method, with server disconnect racing the call
    [ PASS ] test.cpp:379: Calling async IPC method, with server disconnect racing the call (20475 μs)
    [ TEST ] test.cpp:404: Calling async IPC method, with server disconnect after cleanup
    [ PASS ] test.cpp:404: Calling async IPC method, with server disconnect after cleanup (5119 μs)
    [ TEST ] test.cpp:428: Destroying ProxyClient<> with destroy method after peer disconnect
    [ PASS ] test.cpp:428: Destroying ProxyClient<> with destroy method after peer disconnect (14057 μs)
    [ TEST ] test.cpp:454: Make simultaneous IPC calls on single remote thread
    [ PASS ] test.cpp:454: Make simultaneous IPC calls on single remote thread (38471 μs)
    [ TEST ] test.cpp:509: Call async IPC method dispatched to pool thread
    [ PASS ] test.cpp:509: Call async IPC method dispatched to pool thread (16066 μs)
    [ TEST ] test.cpp:553: Call async IPC method without thread or pool errors correctly
    [ PASS ] test.cpp:553: Call async IPC method without thread or pool errors correctly (17293 μs)
    16 test(s) passed 
    
  6. Sjors commented at 7:22 AM on July 10, 2026: member

    Concept ACK on replacing memcpy.

  7. Sjors commented at 7:38 AM on July 10, 2026: member

    ACK fac7b9b7f688a8cdf24577936a0f2e77fe4cf8de

    I was also able to reproduce the error that the new test triggers.

  8. ViniciusCestarii commented at 1:48 PM on July 13, 2026: contributor

    ACK fac7b9b7f688a8cdf24577936a0f2e77fe4cf8de

    Reproduced the error and confirmed fac7b9b7f688a8cdf24577936a0f2e77fe4cf8de fixes it.

  9. ryanofsky approved
  10. ryanofsky commented at 11:46 PM on July 13, 2026: collaborator

    Code review ACK fac7b9b7f688a8cdf24577936a0f2e77fe4cf8de. Thanks for the fix!

    It's still not completely clear to me if this purely a ubsan issue or if there could have been real problems here with compiler optimizations. For example https://developers.redhat.com/articles/2024/12/11/making-memcpynull-null-0-well-defined would seem to suggest that compilers could have used this memcpy to falsely assume result.begin() and data.init() are never null and skip null checks in nearby code. But avoiding memcpy is an improvement in any case.

    Possible followups to this change:

    • There are also other uses of memcpy in the codebase that could be replaced
    • Code would be simpler without the result variable, just using copy(value, output.init(value.size())
  11. ryanofsky merged this on Jul 13, 2026
  12. ryanofsky closed this on Jul 13, 2026

  13. maflcko commented at 6:04 AM on July 14, 2026: contributor

    Code would be simpler without the result variable, just using copy(value, output.init(value.size())

    I am sure the second arg is the beginning of the destination range, so it would have been:

      std::ranges::copy(value, output.init(value.size()).begin());
    

    It's still not completely clear to me if this purely a ubsan issue or if there could have been real problems here with compiler optimizations.

    In the past, this was certainly UB in theory (not sure if a compiler exists in practise to exploit this). I think it is fixed in C29, but it is not clear how fast compilers will apply this fix. (Ref: https://github.com/bitcoin/bitcoin/issues/32016#issuecomment-2759479042)

    There are also other uses of memcpy in the codebase that could be replaced

    Also checked them, but I think they are fine (no promise though).

    There is https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-ranges.html that can be used? Happy to take a look there, if you find it worthwhile.

  14. maflcko deleted the branch on Jul 14, 2026
  15. maflcko commented at 8:33 AM on July 14, 2026: contributor

    There is https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-ranges.html that can be used? Happy to take a look there, if you find it worthwhile.

    Actually, this is unrelated. That check is about moving iterator-based algos to range-based ones.

    For the memcpy replacement, there is https://github.com/llvm/llvm-project/issues/22583


github-metadata-mirror

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

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