Skip to content

Commit e09143d

Browse files
committed
proxy-types: fix UndefinedBehaviorSanitizer: null-pointer-use
Fix UndefinedBehaviorSanitizer: null-pointer-use error binding a null pointer to an unused reference variable. This error should not cause problems in practice because the reference is not used, but is technically undefined behavior. Issue was reported: - Sjors/bitcoin#90 (comment) - https://github.com/Sjors/bitcoin/actions/runs/15921104847/job/44907875067?pr=90 - Sjors/bitcoin#90 (comment) - https://github.com/Sjors/bitcoin/actions/runs/15942739184/job/44973004692?pr=90 and fixed: - Sjors/bitcoin#90 (comment) Error looks like: [ TEST ] test.cpp:197: Call IPC method after client connection is closed /home/runner/work/_temp/src/ipc/libmultiprocess/include/mp/proxy-types.h:612:40: runtime error: reference binding to null pointer of type 'Connection' #0 0x5647ad32fc50 in 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/runner/work/_temp/build-asan/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/include/mp/proxy-types.h:612:25 #1 0x5647ad32b62a in mp::ProxyClient<mp::test::messages::FooInterface>::add(int, int) /home/runner/work/_temp/build-asan/src/ipc/libmultiprocess/test/mp/test/foo.capnp.proxy-client.c++:20:5 #2 0x5647ad2eb9ef in mp::test::TestCase197::run() /home/runner/work/_temp/build-asan/src/ipc/libmultiprocess/test/./ipc/libmultiprocess/test/mp/test/test.cpp:206:14 #3 0x7f6aaf7100e1 (/lib/x86_64-linux-gnu/libkj-test-1.0.1.so+0x50e1) (BuildId: 2ff7f524274168e50347a2d6dd423f273ae8d268) #4 0x7f6aaf710657 (/lib/x86_64-linux-gnu/libkj-test-1.0.1.so+0x5657) (BuildId: 2ff7f524274168e50347a2d6dd423f273ae8d268) #5 0x7f6aaf49f37f in kj::MainBuilder::MainImpl::operator()(kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>) (/lib/x86_64-linux-gnu/libkj-1.0.1.so+0x5537f) (BuildId: 4b52c0e2756bcb53e58e705fcb10bab8f63f24fd) #6 0x7f6aaf49a499 in kj::runMainAndExit(kj::ProcessContext&, kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>&&, int, char**) (/lib/x86_64-linux-gnu/libkj-1.0.1.so+0x50499) (BuildId: 4b52c0e2756bcb53e58e705fcb10bab8f63f24fd) #7 0x7f6aaf70efcb in main (/lib/x86_64-linux-gnu/libkj-test-1.0.1.so+0x3fcb) (BuildId: 2ff7f524274168e50347a2d6dd423f273ae8d268) #8 0x7f6aaeeb81c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 42c84c92e6f98126b3e2230ebfdead22c235b667) #9 0x7f6aaeeb828a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 42c84c92e6f98126b3e2230ebfdead22c235b667) #10 0x5647ad1fd614 in _start (/home/runner/work/_temp/build-asan/src/ipc/libmultiprocess/test/mptest+0x11d614) (BuildId: a172f78701ced3f93ad52c3562f181811a1c98e8) SUMMARY: UndefinedBehaviorSanitizer: null-pointer-use /home/runner/work/_temp/src/ipc/libmultiprocess/include/mp/proxy-types.h:612:40
1 parent 84b292f commit e09143d

File tree

1 file changed

+16
-14
lines changed

1 file changed

+16
-14
lines changed

include/mp/proxy-types.h

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -609,59 +609,61 @@ void clientInvoke(ProxyClient& proxy_client, const GetRequest& get_request, Fiel
609609
<< "{" << g_thread_context.thread_name
610610
<< "} IPC client first request from current thread, constructing waiter";
611611
}
612-
ClientInvokeContext invoke_context{*proxy_client.m_context.connection, g_thread_context};
612+
ThreadContext& thread_context{g_thread_context};
613+
std::optional<ClientInvokeContext> invoke_context; // Must outlive waiter->wait() call below
613614
std::exception_ptr exception;
614615
std::string kj_exception;
615616
bool done = false;
616617
const char* disconnected = nullptr;
617618
proxy_client.m_context.loop->sync([&]() {
618619
if (!proxy_client.m_context.connection) {
619-
const std::unique_lock<std::mutex> lock(invoke_context.thread_context.waiter->m_mutex);
620+
const std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
620621
done = true;
621622
disconnected = "IPC client method called after disconnect.";
622-
invoke_context.thread_context.waiter->m_cv.notify_all();
623+
thread_context.waiter->m_cv.notify_all();
623624
return;
624625
}
625626

626627
auto request = (proxy_client.m_client.*get_request)(nullptr);
627628
using Request = CapRequestTraits<decltype(request)>;
628629
using FieldList = typename ProxyClientMethodTraits<typename Request::Params>::Fields;
629-
IterateFields().handleChain(invoke_context, request, FieldList(), typename FieldObjs::BuildParams{&fields}...);
630+
invoke_context.emplace(*proxy_client.m_context.connection, thread_context);
631+
IterateFields().handleChain(*invoke_context, request, FieldList(), typename FieldObjs::BuildParams{&fields}...);
630632
proxy_client.m_context.loop->logPlain()
631-
<< "{" << invoke_context.thread_context.thread_name << "} IPC client send "
633+
<< "{" << thread_context.thread_name << "} IPC client send "
632634
<< TypeName<typename Request::Params>() << " " << LogEscape(request.toString());
633635

634636
proxy_client.m_context.loop->m_task_set->add(request.send().then(
635637
[&](::capnp::Response<typename Request::Results>&& response) {
636638
proxy_client.m_context.loop->logPlain()
637-
<< "{" << invoke_context.thread_context.thread_name << "} IPC client recv "
639+
<< "{" << thread_context.thread_name << "} IPC client recv "
638640
<< TypeName<typename Request::Results>() << " " << LogEscape(response.toString());
639641
try {
640642
IterateFields().handleChain(
641-
invoke_context, response, FieldList(), typename FieldObjs::ReadResults{&fields}...);
643+
*invoke_context, response, FieldList(), typename FieldObjs::ReadResults{&fields}...);
642644
} catch (...) {
643645
exception = std::current_exception();
644646
}
645-
const std::unique_lock<std::mutex> lock(invoke_context.thread_context.waiter->m_mutex);
647+
const std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
646648
done = true;
647-
invoke_context.thread_context.waiter->m_cv.notify_all();
649+
thread_context.waiter->m_cv.notify_all();
648650
},
649651
[&](const ::kj::Exception& e) {
650652
if (e.getType() == ::kj::Exception::Type::DISCONNECTED) {
651653
disconnected = "IPC client method call interrupted by disconnect.";
652654
} else {
653655
kj_exception = kj::str("kj::Exception: ", e).cStr();
654656
proxy_client.m_context.loop->logPlain()
655-
<< "{" << invoke_context.thread_context.thread_name << "} IPC client exception " << kj_exception;
657+
<< "{" << thread_context.thread_name << "} IPC client exception " << kj_exception;
656658
}
657-
const std::unique_lock<std::mutex> lock(invoke_context.thread_context.waiter->m_mutex);
659+
const std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
658660
done = true;
659-
invoke_context.thread_context.waiter->m_cv.notify_all();
661+
thread_context.waiter->m_cv.notify_all();
660662
}));
661663
});
662664

663-
std::unique_lock<std::mutex> lock(invoke_context.thread_context.waiter->m_mutex);
664-
invoke_context.thread_context.waiter->wait(lock, [&done]() { return done; });
665+
std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
666+
thread_context.waiter->wait(lock, [&done]() { return done; });
665667
if (exception) std::rethrow_exception(exception);
666668
if (!kj_exception.empty()) proxy_client.m_context.loop->raise() << kj_exception;
667669
if (disconnected) proxy_client.m_context.loop->raise() << disconnected;

0 commit comments

Comments
 (0)