Skip to content

Commit 3b2617b

Browse files
committed
Merge #127: ProxyClientBase: avoid static_cast to partially destructed object
63a39d4 ProxyClientBase: avoid static_cast to partially destructed object (Ryan Ofsky) Pull request description: This is a bugfix that should fix the UBSan failure reported #125 In practice there is no real bug here, just like there was no real bug fixed in the recent "ProxyClientBase: avoid static_cast to partially constructed object" change in #121. This is because in practice, ProxyClient subclasses only inherit ProxyClientBase state and do not define any state of their own, so there is nothing bad that could actually happen from static_cast-ing a ProxyClientBase pointer to a ProxyClient pointer inside the ProxyClientBase constructor or destructor. However, using static_cast this way technically triggers undefined behavior, and that causes UBSan to fail, so this commit drops the static_cast by making ProxyClient::construct() and ProxyClient::destroy() methods into static methods taking a ProxyClientBase& argument instead of instance methods using *this. Fixes #125 --- This PR should be a simpler, more robust alternative to a previous for the same bug implemented in #126. Top commit has no ACKs. Tree-SHA512: da55eba1c7f8aeb42e9d34a63793aa2f702c9a2b6e7a17869c35ce24eb188b5ff253a8a975ee8950fe8516ea1fadd1aec22e0755ad3c835bdeb826a18cf8541d
2 parents 621a04a + 63a39d4 commit 3b2617b

File tree

3 files changed

+17
-13
lines changed

3 files changed

+17
-13
lines changed

include/mp/proxy-io.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ ProxyClientBase<Interface, Impl>::ProxyClientBase(typename Interface::Client cli
382382
auto cleanup = m_context.connection->addSyncCleanup([this]() {
383383
// Release client capability by move-assigning to temporary.
384384
{
385-
typename Interface::Client(std::move(self().m_client));
385+
typename Interface::Client(std::move(m_client));
386386
}
387387
{
388388
std::unique_lock<std::mutex> lock(m_context.connection->m_loop.m_mutex);
@@ -412,13 +412,13 @@ ProxyClientBase<Interface, Impl>::ProxyClientBase(typename Interface::Client cli
412412
// the remote object, waiting for it to be deleted server side. If the
413413
// capnp interface does not define a destroy method, this will just call
414414
// an empty stub defined in the ProxyClientBase class and do nothing.
415-
self().destroy();
415+
Sub::destroy(*this);
416416

417417
// FIXME: Could just invoke removed addCleanup fn here instead of duplicating code
418418
m_context.connection->m_loop.sync([&]() {
419419
// Release client capability by move-assigning to temporary.
420420
{
421-
typename Interface::Client(std::move(self().m_client));
421+
typename Interface::Client(std::move(m_client));
422422
}
423423
{
424424
std::unique_lock<std::mutex> lock(m_context.connection->m_loop.m_mutex);
@@ -432,6 +432,7 @@ ProxyClientBase<Interface, Impl>::ProxyClientBase(typename Interface::Client cli
432432
});
433433
}
434434
});
435+
Sub::construct(*this);
435436
}
436437

437438
template <typename Interface, typename Impl>

include/mp/proxy.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ class ProxyClientBase : public Impl_
5656
public:
5757
using Interface = Interface_;
5858
using Impl = Impl_;
59+
using Sub = ProxyClient<Interface>;
60+
using Super = ProxyClientBase<Interface, Impl>;
5961

6062
ProxyClientBase(typename Interface::Client client, Connection* connection, bool destroy_connection);
6163
~ProxyClientBase() noexcept;
@@ -89,10 +91,8 @@ class ProxyClientBase : public Impl_
8991
// then it will also ensure that the destructor runs on the same thread the
9092
// client used to make other RPC calls, instead of running on the server
9193
// EventLoop thread and possibly blocking it.
92-
void construct() {}
93-
void destroy() {}
94-
95-
ProxyClient<Interface>& self() { return static_cast<ProxyClient<Interface>&>(*this); }
94+
static void construct(Super&) {}
95+
static void destroy(Super&) {}
9696

9797
typename Interface::Client m_client;
9898
ProxyContext m_context;

src/mp/gen.cpp

+9-6
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,7 @@ void Generate(kj::StringPtr src_prefix,
357357
client << "public ProxyClientCustom<" << message_namespace << "::" << node_name << ", "
358358
<< proxied_class_type << ">\n{\n";
359359
client << "public:\n";
360-
client << " template <typename... Args>\n";
361-
client << " ProxyClient(Args&&... args) : ProxyClientCustom(std::forward<Args>(args)...) { construct(); }\n";
360+
client << " using ProxyClientCustom::ProxyClientCustom;\n";
362361
client << " ~ProxyClient();\n";
363362

364363
std::ostringstream server;
@@ -531,18 +530,22 @@ void Generate(kj::StringPtr src_prefix,
531530
server_invoke_end << ")";
532531
}
533532

533+
std::string static_str{is_construct || is_destroy ? "static " : ""};
534+
std::string super_str{is_construct || is_destroy ? "Super& super" : ""};
535+
std::string self_str{is_construct || is_destroy ? "super" : "*this"};
536+
534537
client << " using M" << method_ordinal << " = ProxyClientMethodTraits<" << method_prefix
535538
<< "Params>;\n";
536-
client << " typename M" << method_ordinal << "::Result " << method_name << "("
537-
<< client_args.str() << ")";
539+
client << " " << static_str << "typename M" << method_ordinal << "::Result " << method_name << "("
540+
<< super_str << client_args.str() << ")";
538541
client << ";\n";
539542
def_client << "ProxyClient<" << message_namespace << "::" << node_name << ">::M" << method_ordinal
540543
<< "::Result ProxyClient<" << message_namespace << "::" << node_name << ">::" << method_name
541-
<< "(" << client_args.str() << ") {\n";
544+
<< "(" << super_str << client_args.str() << ") {\n";
542545
if (has_result) {
543546
def_client << " typename M" << method_ordinal << "::Result result;\n";
544547
}
545-
def_client << " clientInvoke(*this, &" << message_namespace << "::" << node_name
548+
def_client << " clientInvoke(" << self_str << ", &" << message_namespace << "::" << node_name
546549
<< "::Client::" << method_name << "Request" << client_invoke.str() << ");\n";
547550
if (has_result) def_client << " return result;\n";
548551
def_client << "}\n";

0 commit comments

Comments
 (0)