Search code examples
cpointerslanguage-lawyerc11strict-aliasing

How does malloc work with strict aliasing - can it only be violated within a single compilation unit?


After reading this, I have a similar question like this one, wondering how a memory allocator can work without violating the strict aliasing rules. But I am not wondering about re-using freed memory, I wonder about how allocated objects can be positioned within linear memory without violating strict aliasing.

All heap memory allocators I have looked at so far divide their memory in some sort of blocks, with a header in front. However, malloc returns a void * and usually points to the memory right after the header. Here is an extremely narrowed down example to illustrate this.

#include <stddef.h>

struct block_header {
  size_t size;
};

struct block_header *request_space(size_t size);

void *malloc(size_t size) {
    struct block_header *block = request_space(size);

    // I guess this violates strict aliasing, because the caller will 
    // convert the pointer to something other than struct block_header?
    // Or why wouldn't it?
    return block + 1;
}

I have been looking at this for a while now, but I see no way how an allocator could possibly position it's pointers in a memory region without violating strict aliasing. What am I missing?


Solution

  • According to the standard, these things never violate strict aliasing:

    • Casting a pointer.
    • Doing pointer arithmetic.
    • Writing into malloc'd space.

    The thing you are not allowed to do in malloc'd space is read some memory as a different type than it was written as (except for the list of allowed aliasing types of course).

    The text of the rule is in C11 6.5/7:

    An object shall have its stored value accessed only by [...]

    and the text in 6.5/6 explains that if we are in malloc'd space then the write imprints the type of the write onto the destination (and therefore there cannot be a type mismatch).

    The code you've posted so far never does the forbidden thing so there is no apparent problem. There would only be a problem if someone used your allocator and then read the memory without writing it .

    Footnote 1: 6.5/6 apparently is defective according to the committee response to DR236 but never fixed so who knows where that leaves us.

    Footnote 2: as Eric points out the standard doesn't apply to implementation internals, but consider my comments in the context of some user-written allocator as in the other question you linked to.