Comment by matheusmoreira

3 years ago

> The reverse is not true: if the dynamic type of an object is char, just by using the alias rules, you can't deference it as an object of a different type.

A limitation like that simply makes no sense to me. Everything is a valid char array but I can't place structs on top of one? Oh well, nothing I can do about it. I'll just keep strict aliasing disabled. If we're writing C, it's because we want to do stuff like that without the compiler getting clever about it.

> you should be able to change the type of anonymous memory (for example, what is allocated with malloc) by simply writing into it

Well, in my case, I'm the one writing the malloc and the buffer is the anonymous memory. I remember months ago I scoured the GCC documentation for some kind of builtin that would allow me to mark the memory as such but there was nothing. I did add some malloc attributes to my allocation function just like TFA suggested but apparently its main purpose is to optimize based on aliasing nonsense which I disabled anyway.

At some point you need to get the memory for your pool from somewhere, for example from malloc [1], hence you can safely set the type of the raw memory by writing into it. You can also change that type to some other type, by writing other stuff (so you can reuse the memory). You can also write metadata to it between uses. What you cannot do is having overlapping lifetimes for different types.

Making sure that you respect all the underspecified, obscure, and often contradicting rules is not easy, so if you prefer to disable strict-alias, you have my sympathy. For the most part is useful for high performance numerical code, and less advantageous for typical pointer chasing stuff.

From the practical point of view, the safest way to implement a custom allocator is to make sure that the compiler can't see through it, so separate compilation and no LTO and/or launder your pointers through appropriate inline asm.

[1] but other 'anonymous' sources, like mmap, would also work in practice.

  • > For the most part is useful for high performance numerical code, and less advantageous for typical pointer chasing stuff.

    Yeah. I've read that the aliasing rules and features like restrict were introduced to C because Fortran had them.

    > the safest way to implement a custom allocator is to make sure that the compiler can't see through it

    Makes sense.

    > launder your pointers through appropriate inline asm

    This is a really neat trick indeed. I learned a lot today.

> Everything is a valid char array but I can't place structs on top of one? Oh well, nothing I can do about it. I'll just keep strict aliasing disabled.

Well, yeah. Strict aliasing is less about the incidental values of memory addresses and more about the actual semantics of what you're doing. Where writing a struct into the middle of a char array makes no sense because you have no guarantee in the type system that the array is properly sized or aligned to contain that struct.

  • The compiler knows the size of statically allocated buffers and can be told about alignments with:

      __attribute__((aligned(N)))
      __builtin_assume_aligned(P, N)
    

    Is this information sufficient for correct code generation?

    • Strict aliasing doesn't allow the compiler to magically decide that someplace you are writing happens to be in a statically allocated buffer. Strict aliasing says you have a pointer of some type and what you do with it has to agree with the type of that pointer.

I feel like there should be a builtin that takes a void* and returns a void* which basically marks the input as aliased by the returned pointer regardless of the TBAA rules.

  • Turns out there is! __builtin_launder seems mostly equivalent to what the author proposes but probably more reliable. Facebook’s folly library appears to use both, preferring the builtin.