Segmentation fault when using GET method.

38 views
Skip to first unread message

Diogo Leitão

unread,
Nov 3, 2019, 1:18:23 AM11/3/19
to Cap'n Proto
Hi

I'm using FUSE + Cap'n Proto to build a distributed filesystem. Everything seems to be fine, but when i try get the data field, on the client side, using the getBuf method, i get a segmentation fault error. 
 
This is the code that i made. What am i doing wrong?  


/*
 * Capnp source file
 */
interface FilesystemOps {
    ...
read @16 (request :ReadRequest) -> (reply :ReadReply);
    ...
}

struct ReadRequest {
path @0 :Text;
size @1 :UInt64;
offset @2 :Int64;
}

struct ReadReply {
result @0 :Int32;
buf @1 :Data;
}

/*
 * Client side
 */
int FilesystemOpsClient::rpc_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
std::cout << "rpc_read begin " << size << std::endl;

int res;
auto clientData = getClient();
auto request = clientData->cap_.readRequest();
auto builder = request.getRequest();

builder.setPath(path);
builder.setSize(size);
builder.setOffset(offset);

auto reply = request.send().wait(clientData->waitScope_).getReply();

res = reply.getResult();
if (res != -1) {
  std::memcpy(buf, reply.getBuf().begin(), res);
    }

return res;
}

/*
 * Server side
 */
kj::Promise<void> FilesystemOpsImpl::read(FilesystemOps::Server::ReadContext context) {
int res;
auto request = context.getParams().getRequest();
auto reply = context.getResults().getReply();

std::string path = root_path_ + request.getPath().cStr();
size_t size = request.getSize();
off_t offset = request.getOffset();

int fd = ::open(path.c_str(), O_RDONLY);
if (fd == -1) {
res = -
1;
} else {
res = pread(fd
, reply.initBuf(size).begin(), size, offset);
close(fd);
}

reply.setResult(res);

return kj::READY_NOW;
}

Appreciate your help. Thank you. 

Paweł Głodny R.

unread,
Nov 3, 2019, 1:10:43 AM11/3/19
to Cap'n Proto
Look at the line you mentioned yourself: "std::memcpy(buf,
reply.getBuf().begin(), res);". You probably meant "size" instead of
"res".
What's the output of "res = reply.getResult();" exactly? Unless it's
not the size, you've got logic error and "memcpy" may go out-of-range
when copying data.
Does the destination buffer have enough space to hold all the copied
data (you might need to guarantee it explicitly - it won't resize on
it's own)?
What's the type of "reply.getBuf().begin()"? Remember that "memcpy"
operates on raw pointers.

-Paweł
> --
> You received this message because you are subscribed to the Google Groups "Cap'n Proto" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to capnproto+...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/capnproto/ee51e0ec-819c-4962-9245-41cafcd03862%40googlegroups.com.

Diogo Leitão

unread,
Nov 3, 2019, 2:18:05 PM11/3/19
to Cap'n Proto
The "size" it's the amount of bytes that the FUSE wants to read, and "res" it's the amount of bytes that were read. 
The syscall pread ensures that "size" is always greater or equal than "res". If an error occurred during the this syscall "res" will be -1, but in this case "memcpy" isn't called . 
FUSE also guarantees that the destination buffer as enough space to hold the amounted bytes that requested, that is, "size" value. 

I have already tested other methods related to buf field on the capnp struct, like hasBuf, and i also get segmentation fault. 

I forgot to say that this code works on my MacBook, but when a try it on a different OS (Ubuntu 18.04 or Ubuntu 16.04) it fails. I have already compiled it with different compilers (g++ and clang++) with old and new versions. But nothing seems to solve the problem. 
> To unsubscribe from this group and stop receiving emails from it, send an email to capn...@googlegroups.com.

Kenton Varda

unread,
Nov 3, 2019, 2:41:28 PM11/3/19
to Diogo Leitão, Cap'n Proto
Hi Diogo,

The problem is with this line:

    auto reply = request.send().wait(clientData->waitScope_).getReply();

On this line, `wait()` will return a `capnp::Response<ReadResults>`. This response object owns the underlying reply message. But you are immediately calling `getReply()` on it and then throwing away the response object. Note that struct Reader and Builder objects are essentially pointers into the message buffer. Thus, `reply` is now pointing into a message that has been thrown away. You need to do this instead:

    auto response = request.send().wait(clientData->waitScope_);
    auto reply = response.getReply();

This way, `response` will live until the end of the current scope, so `reply` is not a dangling pointer.

-Kenton

To unsubscribe from this group and stop receiving emails from it, send an email to capnproto+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/capnproto/bd19f6da-b288-4c17-80ae-b14e2f903d1c%40googlegroups.com.

Diogo Leitão

unread,
Nov 3, 2019, 2:54:36 PM11/3/19
to Cap'n Proto
That was the problem, now it's solved. 
Thank you both for your time. 
Keep the great work. 
Reply all
Reply to author
Forward
0 new messages