When passing file descriptors over Unix domain sockets, control messages at level SOL_SOCKET
of type SCM_RIGHTS
are used.
Control messages are read and written using the macros CMSG_FIRSTHDR
, CMSG_NXTHDR
and CMSG_DATA
. They take alignment issues into account. Depending on the operating system and libc implementation, they cast pointers and dereference the result either in the same or a different translation unit. They also return such pointers and the calling code typically dereferences them.
As a result, using a simple stack-allocated char buf[CMSG_SPACE(sizeof(int))]
as a control message buffer will violate strict-aliasing as the buffer may only be accessed using lvalues of type char
, signed char
, unsigned char
or qualified versions of those. (On some platforms, the buffer might also not be suitably aligned, but the amd64 calling conventions appear to guarantee this because the buffer is large enough.)
An obviously correct fix is to allocate the control message buffer using calloc()
, which provides suitably aligned memory without an effective type. However, I would like to avoid making the program less efficient.
In https://svnweb.freebsd.org/base/head/lib/libopenbsd/imsg.c?revision=292023&view=markup I found a different approach where the stack buffer is of type union { struct cmsghdr hdr; char buf[CMSG_SPACE(sizeof(int))]; }
, but I don't know whether that is correct. I guess it helps that struct cmsghdr
has a field of type int
.
Extra question: how to do this in C++ given that C++ has different rules about (among other things) unions than C?