Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a standards-compliant way to do zero-copy IPC in C++?

I have an application that currently reads data from a stream (socket, named, pipe, stdin, whatever) into a char buffer and then uses reinterpret_cast to point a Foo * (where Foo is a POD) into the middle of the buffer and then works with the contents of the buffer through that pointer.

Now, this breaks strict aliasing rules, though I doubt that it would actually cause a problem in practice. Still, is there an accepted way to do this in Standard C++? Because we're potentially transferring 100s of gigabytes this way, and do not want to, under any circumstances, introduce the overhead of copying this data out of the buffer into a structure with memcpy.

To be clear, the code looks something like this:

MessageData *msg = new MessageData();
while (ipc.we_have_data()) {
   ipc.read(msg);
   char *buf = msg->data();
   Header *h = reinterpret_cast<Header *>(buf);
   if (h->tag == 0) {
      Payload *p = reinterpret_cast<Payload *>(buf + sizeof(Header));
      do_stuff_with_payload(p);
   } else if (h->tag == 1) {
      // etc...
   }
}

I realize there may be alignment issues, but they do not concern me at this point. The data is being produced on the same platform by the same compiler, so there are no issues with the layout of structure members being different. But, as I understand it, this technically breaks strict aliasing rules.

Is there an efficient way to do this that doesn't break strict aliasing rules?

Or am I completely wrong, and it's just fine by these rules?

If so, why?

Edit: A deleted comment pointed to this definition of the aliasing rules that says char * gets a free pass. So, my example actually doesn't break strict aliasing rules. Does anybody know the right section of the standard for this?

like image 581
Omnifarious Avatar asked Nov 07 '22 20:11

Omnifarious


1 Answers

Unfortunately, the standard is not very friendly for processing structured data read into a buffer of characters. Only the opposite is allowed: if you know that you are going to read a POD object, you can build one and pass its address converted to a char pointer to any function that will be able to fill it with actual data, and then use it normally.

The free pass provided by char * only allows to process an object at a byte level, but the strict aliasing rule normally forbids to decide that a char buffer actually contains an object. Anyway, the higher risk here would be an alignment issue.

For the rest, specific implementations of compilers are perfectly allowed to ignore the strict aliasing rule. What happens then is undefined by standard but can be perfectly defined by a compiler provided you pass it the appropriate flag. Your program may then break with a different compiler or a different configuration of the same compiler, so it will have portability issues, but that may be acceptable provided it is clearly documented - and you are sure that no alignment issue may arise...

like image 179
Serge Ballesta Avatar answered Nov 14 '22 21:11

Serge Ballesta