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

Viewed 339

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?

3 Answers

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.

The source code of malloc is not required to conform to the C standard in the way that normal source code is. It is part of the C implementation.

The people who work on malloc, the compiler, and other parts of the C implementation are responsible for ensuring they work together. That can include the compiler treating malloc specially and malloc using behaviors that are guaranteed to it by the C compiler but not by the C standard.

The C Standard deliberately avoids requiring that all implementations be suitable for all purposes. It is instead designed to allow implementations intended for various purposes to, as a form of "conforming language extension", process constructs meaningfully in ways that would be useful for those purposes even when the Standard imposes no requirements. Thus, the Standard allows implementations intended for tasks requiring manual memory management to support "popular extensions" that facilitate such tasks, even though it deliberately avoids requiring such support from implementations that aren't intended for such tasks.

Many kinds of memory allocators would be impractical to implement on implementations whose semantics are limited to those mandated by the Standard. Implementations that uphold the Spirit of C principle described by the Committee as "Don't prevent the programmer from doing what needs to be done", however, and are designed and configured to be suitable for building such allocators, however, will recognize indications that storage will be used as more than one type. The exact range of situations where compilers recognize such indications was left as a "quality of implementation" issue outside the Standard's jurisdiction. From a practical standpoint, the authors of clang and gcc have opted to behave in minimal-allowable-quality fashion except when using -fno-strict-aliasing, but all that means is that programmers who want to do anything "interesting" with those compilers must use that option. There is no evidence whatsoever that the authors of the Standard intended that programmers should be expected to jump through hoops to accommodate the limitations of poor-quality implementations; instead, they expected that the market would be better placed than the Committee to judge how compilers should most usefully behave to accomplish various tasks.

Related