Whilst developing Privilege Separation in dhcpcd, I had to come up with an IPC design for it. Of course, that involves creating structures.

So far, my structures in dhcpcd are long lived- or rather the scope is design to live outside of where it was created. As such they are created on the heap and are at the mercy of malloc. Generally I use calloc so that the whole area is inited to zero as uninitialised memory is bad.

So I decided to start out and see if I can just create the structures I need on the stack. Turns out I could! Yay! Now, how to you initialise a structure on the stack to all zeros? First let us consider this structure:

struct ps_addr {
	sa_family_t psa_family;
	union {
		struct in_addr psau_in_addr;
		struct in6_addr psau_in6_addr;
	} psa_u;
#define	psa_in_addr		psa_u.psau_in_addr
#define	psa_in6_addr	psa_u.psau_in6_addr
};

The first way is memset:

struct ps_addr psa;

memset(&psa, 0, sizeof(psa));
psa.psa_family = AF_INET;

But what if you could avoid memset? Luckily the C standard allows setting any member and will zero all other members. So we can do this:

struct ps_addr psa = { .psa_family = AF_INET };

Wow!!! So simple. This reduces binary size a fair bit. But then I turned on the Memory Sanitiser and boom, it crashed hard. Why?

The answer is simple- padding. Eric S Raymond gives a very good writeup about the problem. Basically, the standard will initialise any unintialised members to zero- but padding added for alignent isn’t a member! So we need to ensure that our structure requires zero padding.

Here is the new struct:

struct ps_addr {
	sa_family_t psa_family;
	uint8_t psa_pad[4- sizeof(sa_family_t)];
	union {
		struct in_addr psau_in_addr;
		struct in6_addr psau_in6_addr;
	} psa_u;
#define	psa_in_addr		psa_u.psau_in_addr
#define	psa_in6_addr	psa_u.psau_in6_addr
};

And it allows the former structure initialisation to work and memory sanitisers are happy- so happy days :) Now, if anyone can tell me what I can use instead of the magic number 4 in the above I’d be even happier!