Call to `thisCap()` segfaults

95 views Asked by At

I am playing with the calculator-server.c++ sample, where I try to extract thisCap() to have a capability to the server from outside. Because thisCap() is protected, I wrote my own public getCapability():

class CalculatorImpl final: public Calculator::Server {
  // Implementation of the Calculator Cap'n Proto interface.

public:
  Calculator::Client getCapability() {
      return thisCap();
  }

Then I create the server and call getCapability() from my main:

  auto calculatorImpl = kj::heap<CalculatorImpl>();
  auto myCapability = calculatorImpl->getCapability();

But this segfaults:

Program received signal SIGSEGV, Segmentation fault.
0x000055555573c847 in capnp::Capability::Server::thisCap() ()
(gdb) bt
#0  0x000055555573c847 in capnp::Capability::Server::thisCap() ()
#1  0x000055555573c93d in Calculator::Server::thisCap() ()
#2  0x000055555573e541 in CalculatorImpl::getCapability() ()
#3  0x0000555555739a98 in main ()

Following the source, I end up on this:

Capability::Client Capability::Server::thisCap() {
  return Client(thisHook->addRef());
}

So it seems like thisHook is a nullptr, which makes sense since that's how it is initialized.

I just don't really get at which point it get initialized (this explains when it is definitely not initialized).

Any idea?

1

There are 1 answers

2
Kenton Varda On BEST ANSWER

thisCap() only works after at least one Client object has been created pointing at your server object. To create that initial Client, you can simply declare a variable of the client type and initialize it to your server object, like so:

Calculator::Client cap = kj::heap<CalculatorImpl>();

If you want to keep a reference to the underlying server object even after constructing a Client, you can do something like:

kj::Own<CalculatorImpl> server = kj::heap<CalculatorImpl>();
CalculatorImpl& ref = *server;
Calculator::Client cap = kj::mv(server);

Note that once the first Client has been created, the server will be destroyed as soon as there are no longer any Clients pointing to it (including remote Clients). So if you want to make sure your reference stays live, make sure you also keep a copy of the Client.

Normally, thisCap() is used inside the implementation of RPC methods. It's unusual to expose it to external callers in the way you have with your getCapability() method. This is because if the caller isn't already holding a Client pointing to the object, then it has no way to know if the object still exists, and so it would be unsafe to call a method like getCapability().