Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

segfault caused by GC'ed connection #5

Open
dwrensha opened this issue Sep 27, 2014 · 1 comment
Open

segfault caused by GC'ed connection #5

dwrensha opened this issue Sep 27, 2014 · 1 comment

Comments

@dwrensha
Copy link
Member

test.capnp:

@0x8314444a113b636e;

interface Foo {
  bar @0 () -> ();
}

test-server.c++:

#include "test.capnp.h"
#include <capnp/ez-rpc.h>
#include <iostream>
#include <unistd.h>

class FooImpl final: public Foo::Server {
public:
  kj::Promise<void> bar(BarContext context) override {
    std::cout << "inside of bar\n";
    usleep(1000000);
    return kj::READY_NOW;
  }
};

int main(int argc, const char* argv[]) {
  if (argc != 2) {
    std::cerr << "usage: " << argv[0] << " ADDRESS[:PORT]\n"
    "Runs the server bound to the given address/port.\n"
    "ADDRESS may be '*' to bind to all local addresses.\n"
      ":PORT may be omitted to choose a port automatically." << std::endl;
    return 1;
  }

  capnp::EzRpcServer server(argv[1]);
  server.exportCap("foo", kj::heap<FooImpl>());

  auto& waitScope = server.getWaitScope();
  uint port = server.getPort().wait(waitScope);
  std::cout << "Listening on port " << port << "..." << std::endl;

  kj::NEVER_DONE.wait(waitScope);
}

test.js:

Capnp = require('capnp');
Foo = Capnp.import('test.capnp').Foo;

var conn = Capnp.connect("127.0.0.1:1234");
var cap = conn.restore("foo", Foo);

cap.bar().then(function(result) {
    console.log("got it");
}).catch(function(err) {
    console.log("error: " + err);
});
setTimeout(function() {
    console.log("garbage collecting...");
    global.gc();
}, 0);

I start the server in one terminal:

$ ./test-server 127.0.0.1:1234
Listening on port 1234...

And in the other I start the client:

$ node --expose-gc test.js
garbage collecting...
Segmentation fault (core dumped)

Sometimes, instead of the segfault I get:

$ node --expose-gc test.js
garbage collecting...
error: Error: Disconnected: RpcSystem was destroyed.

The problem goes away if I force conn to live long enough, e.g. by putting var x = conn; inside the then callback.

@kentonv
Copy link
Member

kentonv commented Oct 7, 2014

Ugh. There's no good way in the C++ API to track which capabilities need which connections to stay open, so we can't really do the GC "correctly". I think what we probably need to do is maintain a singleton connection pool. Connections are kept in a map and a second attempt to connect to the same destination returns the same connection, until you explicitly call close().

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

No branches or pull requests

2 participants