I have defined a union as follows:
union {
uintptr_t refcount;
struct slab_header *page;
} u;
The page pointer is guaranteed to be aligned on a page boundary (most probably 4096), and is never going to be NULL. This implies that the lowest possible address is going to be 4096.
refcount will be within 0 .. 4095.
Upon the creation of the enclosing struct, I can either have u.refcount = 0 or u.page = mmap(...).
The code around this union is going to be something like that:
if (u.refcount < 4096) {
/* work with refcount, possibly increment it */
} else {
/* work with page, possibly dereference it */
}
Is this always guaranteed to work on a fully POSIX-compliant implementation? Is it ever possible that uintptr_t and struct slab_header * have different representations, so that, for example, when u.page == 8192, u.refcount < 4096 yields true?
I don’t think that it’s “always guaranteed to work”, because:
uintptr_tis optional (7.18.1.4).void *can be converted touintptr_tand back (7.18.1.4). It’s not guaranteed that it is the case withstruct slab_header*. Avoid *has the same representation and alignment requirements as a pointer to a character type. Pointers to structures needn’t have the same representation or alignment (6.2.5 27). Even if this was not the case, nothing guaranteessizeof(uintptr_t) == sizeof(void *), it could obviously be larger and still satisfy the requirement of being convertible tovoid *in the typical case of homogeneous pointers.Therefore, I’d conclude the best way would be to have a common initial elements that tells the state.