Skip to content

Protobuf → IPC debugging

Zach Day edited this page Aug 5, 2020 · 2 revisions

Foreword

When including strings in protobufs sent over IPC messages (sending from client to server), I began to encounter a strange bug in which I would receive the message successfully, but attempting to unpack the protobuf object from the message body would yield NULL. After some experimentation I realized that the issue seems to only manifest itself when there are strings of specific lengths in the message.

Testing

These examples involve sending the RegisterClientMessage over a pipe managed by NNG. Note the string length, the message length (as given by nng_msg_len), and the return value of the protobuf unpack.

string (length) message size effect
/tmp/te (7) 22 null
/tmp/tes (8) 24 success
/tmp/test (9) 26 null
/tmp/testx (10) 28 success

An apparent behavior of the protobuf is that adding a byte to the string increases the size of the message by two bytes. This is probably normal behavior from the library, though.

There is pretty obvious pattern in that table: if the size of the message divided by two is odd, the unpacking fails. This explains why the bug only manifests with strings -- the only other data type we have been using is int32 and oneof (which is just a union with an int32 designating the member). Those data types add 4 bytes to the message, so the length/2 was always even.

Solution

When I have time I will try to make a minimal example of this to show to protobuf-c or NNG devs. For the time being, though, an easy fix is as follows. This is the fix as performed in the sunneed server; for the client-side, SunneedRequest would be replaced by SunneedResponse.

nng_msg *msg;

// ...receive message over IPC

size_t msg_len = nng_msg_len(msg);
if ((msg_len / 2) % 2 == 1)
    msg_len++;
SunneedRequest *request = sunneed_request__unpack(NULL, msg_len, nng_msg_body(msg));

There's definitely more to this issue (why does adding specifically 1 solve it) but I've tested this a bunch and never got NULL.